diff --git a/.github/ISSUE_TEMPLATE/03-mobile.yml b/.github/ISSUE_TEMPLATE/03-mobile.yml index 7c6de5aad523d..07bb40ff94a2e 100644 --- a/.github/ISSUE_TEMPLATE/03-mobile.yml +++ b/.github/ISSUE_TEMPLATE/03-mobile.yml @@ -131,6 +131,6 @@ body: id: ep-version attributes: label: Execution Provider Library Version - placeholder: ex. CUDA 11.6 or ROCm 5.1.1 + placeholder: ex. CUDA 12.2 or ROCm 5.1.1 validations: required: false diff --git a/.github/ISSUE_TEMPLATE/05-performance.yml b/.github/ISSUE_TEMPLATE/05-performance.yml index da0e6c7ada7a7..5d678033f6a42 100644 --- a/.github/ISSUE_TEMPLATE/05-performance.yml +++ b/.github/ISSUE_TEMPLATE/05-performance.yml @@ -127,7 +127,7 @@ body: id: ep-version attributes: label: Execution Provider Library Version - placeholder: ex. CUDA 11.6 or ROCm 5.1.1 + placeholder: ex. CUDA 12.2 or ROCm 5.1.1 validations: required: false - type: textarea diff --git a/.github/ISSUE_TEMPLATE/06-training.yml b/.github/ISSUE_TEMPLATE/06-training.yml index 790d64dac0051..fec2ab3a1b285 100644 --- a/.github/ISSUE_TEMPLATE/06-training.yml +++ b/.github/ISSUE_TEMPLATE/06-training.yml @@ -72,6 +72,6 @@ body: id: ep-version attributes: label: Execution Provider Library Version - placeholder: ex. CUDA 11.6 or ROCm 5.1.1 + placeholder: ex. CUDA 12.2 or ROCm 5.1.1 validations: required: false diff --git a/.github/ISSUE_TEMPLATE/08-general.yml b/.github/ISSUE_TEMPLATE/08-general.yml index 241be0044fe7d..53269c240429f 100644 --- a/.github/ISSUE_TEMPLATE/08-general.yml +++ b/.github/ISSUE_TEMPLATE/08-general.yml @@ -125,6 +125,6 @@ body: id: ep-version attributes: label: Execution Provider Library Version - placeholder: ex. CUDA 11.6 or ROCm 5.1.1 + placeholder: ex. CUDA 12.2 or ROCm 5.1.1 validations: required: false diff --git a/.github/actions/install-onnxruntime-wheel/action.yml b/.github/actions/install-onnxruntime-wheel/action.yml new file mode 100644 index 0000000000000..07f9a00a1dbcf --- /dev/null +++ b/.github/actions/install-onnxruntime-wheel/action.yml @@ -0,0 +1,18 @@ +name: 'Install ONNX Runtime Wheel' +description: 'Uninstalls existing ONNX Runtime packages and installs a wheel from a specified directory.' +inputs: + whl-directory: + description: 'The directory containing the ONNX Runtime wheel files.' + required: true +runs: + using: 'composite' + steps: + - name: Uninstall onnxruntime packages + shell: pwsh + run: | + python -m pip uninstall -y onnxruntime onnxruntime-gpu onnxruntime-training onnxruntime-directml -qq + + - name: Install onnxruntime wheel from specified directory + shell: pwsh + run: | + Get-ChildItem -Path ${{ inputs.whl-directory }}/*.whl | foreach {pip --disable-pip-version-check install --upgrade $_.fullname} \ No newline at end of file diff --git a/.github/actions/linux-web-init-and-check/action.yml b/.github/actions/linux-web-init-and-check/action.yml new file mode 100644 index 0000000000000..c250f368a953e --- /dev/null +++ b/.github/actions/linux-web-init-and-check/action.yml @@ -0,0 +1,71 @@ +name: "Web Build Initialize and Check on Linux" +description: "Initializes and checks the ONNX Runtime Web build on Linux." +runs: + using: "composite" + steps: + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: "22.x" + + - name: npm ci /js/ + run: npm ci + shell: bash + working-directory: ${{ github.workspace }}/js + + - name: npm ci /js/common/ + run: npm ci + shell: bash + working-directory: ${{ github.workspace }}/js/common + + - name: run onnxruntime-common tests + run: npm test + shell: bash + working-directory: ${{ github.workspace }}/js/common + + - name: run onnxruntime-common tests (enable Float16Array) + run: npm run test:f16 + shell: bash + working-directory: ${{ github.workspace }}/js/common + + - name: npm ci /js/web/ + run: npm ci + shell: bash + working-directory: ${{ github.workspace }}/js/web + + - name: run TypeScript type check in /js/web/ + run: npm run prebuild + shell: bash + working-directory: ${{ github.workspace }}/js/web + + - name: run ESLint + run: npm run lint + shell: bash + working-directory: ${{ github.workspace }}/js + + - name: Format code + run: npm run format + shell: bash + working-directory: ${{ github.workspace }}/js + + - name: Check unformatted files + run: | + node -e "a=require('child_process').execSync('git diff --name-only').toString();if(a)throw new Error('Following source files are not formatted: (did you run \"npm run format\"?)\n'+a)" + shell: bash + working-directory: ${{ github.workspace }}/js + + - name: TypeDoc Validation + run: npx typedoc --emit none --treatWarningsAsErrors + shell: bash + working-directory: ${{ github.workspace }}/js/common + + - name: Generating documents + run: npm run build:doc + shell: bash + working-directory: ${{ github.workspace }}/js/web + + - name: Check out of dated documents + run: | + node -e "a=require('child_process').execSync('git diff --name-only').toString();if(a)throw new Error('Following documents are not up-to-date: (did you run \"npm run build:doc\"?)\n'+a)" + shell: bash + working-directory: ${{ github.workspace }}/js/web diff --git a/.github/actions/locate-vcvarsall-and-setup-env/action.yml b/.github/actions/locate-vcvarsall-and-setup-env/action.yml new file mode 100644 index 0000000000000..2fe3658b465c0 --- /dev/null +++ b/.github/actions/locate-vcvarsall-and-setup-env/action.yml @@ -0,0 +1,80 @@ +name: 'Locate vcvarsall and Setup Environment' +description: 'Locates vcvarsall.bat, sets up the environment, and handles PATH updates.' +inputs: + architecture: + description: 'Target architecture (x64 or x86)' + required: true + default: 'x64' +outputs: + vcvarsall_path: + description: "Path to vcvarsall.bat" + value: ${{ steps.find-vcvarsall.outputs.vcvarsall_path }} +runs: + using: "composite" + steps: + + - name: Setup VCPKG + uses: microsoft/onnxruntime-github-actions/setup-build-tools@v0.0.5 + with: + vcpkg-version: '2025.03.19' + vcpkg-hash: '17e96169cd3f266c4716fcdc1bb728e6a64f103941ece463a2834d50694eba4fb48f30135503fd466402afa139abc847ef630733c442595d1c34979f261b0114' + cmake-version: '3.31.6' + cmake-hash: '0f1584e8666cf4a65ec514bd02afe281caabf1d45d2c963f3151c41484f457386aa03273ab25776a670be02725354ce0b46f3a5121857416da37366342a833a0' + add-cmake-to-path: 'true' + disable-terrapin: 'false' + + - name: Verify vcpkg setup + shell: pwsh # Use powershell to easily access env var + run: | + Write-Host "VCPKG_INSTALLATION_ROOT is set to: $env:VCPKG_INSTALLATION_ROOT" + & "$env:VCPKG_INSTALLATION_ROOT/vcpkg" version + + - name: Find vcvarsall.bat + id: find-vcvarsall + shell: python # Use Python shell + run: | + import os + import subprocess + + vswhere_path = os.path.join(os.environ["ProgramFiles(x86)"], "Microsoft Visual Studio", "Installer", "vswhere.exe") + + try: + process = subprocess.run([vswhere_path, "-latest", "-property", "installationPath"], capture_output=True, text=True, check=True) + vs_install_path = process.stdout.strip() + vcvarsall_path = os.path.join(vs_install_path, "VC", "Auxiliary", "Build", "vcvarsall.bat") + + if os.path.exists(vcvarsall_path): + print(f"vcvarsall found at: {vcvarsall_path}") + # Use GITHUB_OUTPUT environment variable + with open(os.environ['GITHUB_OUTPUT'], 'a') as f: + f.write(f"vcvarsall_path={vcvarsall_path}\n") + else: + print(f"vcvarsall.bat not found at expected path: {vcvarsall_path}") + # Use 'exit(1)' for Python to properly signal failure to GitHub Actions + exit(1) + + + except subprocess.CalledProcessError as e: + print(f"Error running vswhere.exe: {e}") + print(f"vswhere output: {e.stdout}") + print(f"vswhere stderr: {e.stderr}") + exit(1) # Exit with a non-zero code on error + except FileNotFoundError: + print(f"vswhere.exe not found at: {vswhere_path}") + exit(1) + + + - name: Setup Environment + shell: cmd + run: | + REM Get initial environment variables + set > initial_env.txt + + REM Call vcvarsall.bat using the output from the previous step + call "${{ steps.find-vcvarsall.outputs.vcvarsall_path }}" ${{ inputs.architecture }} + + REM Get environment variables after calling vcvarsall.bat + set > final_env.txt + + REM Call the Python script to update the GitHub Actions environment + python ${{ github.action_path }}\update_environment.py diff --git a/.github/actions/locate-vcvarsall-and-setup-env/locate_vcvarsall.bat b/.github/actions/locate-vcvarsall-and-setup-env/locate_vcvarsall.bat new file mode 100644 index 0000000000000..df900e5cd0995 --- /dev/null +++ b/.github/actions/locate-vcvarsall-and-setup-env/locate_vcvarsall.bat @@ -0,0 +1,30 @@ +@echo off +setlocal + +set vswherepath="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" +set vcvarsall_arch=%1 +if "%vcvarsall_arch%" == "x86" ( + set vcvarsall_arch=x86 +) else ( + set vcvarsall_arch=x64 +) + +for /f "usebackq delims=" %%i in (`%vswherepath% -latest -property installationPath`) do ( + if exist "%%i\VC\Auxiliary\Build\vcvars%vcvarsall_arch%.bat" ( + set "vcvarsall=%%i\VC\Auxiliary\Build\vcvars%vcvarsall_arch%.bat" + ) +) + +echo "Get initial environment variables" +set > initial_env.txt + +echo "Call vcvarsall.bat" +call "%vcvarsall%" + +echo "Get environment variables after calling vcvarsall.bat" +set > final_env.txt + +echo "Call the Python script to update the GitHub Actions environment" +python "%~dp0\update_environment.py" + +endlocal \ No newline at end of file diff --git a/.github/actions/locate-vcvarsall-and-setup-env/update_environment.py b/.github/actions/locate-vcvarsall-and-setup-env/update_environment.py new file mode 100644 index 0000000000000..9b63b26042562 --- /dev/null +++ b/.github/actions/locate-vcvarsall-and-setup-env/update_environment.py @@ -0,0 +1,37 @@ +import os +import re + + +def read_env_file(filepath): + env_vars = {} + with open(filepath) as f: + for line in f: + match = re.match(r"^(.*?)=(.*)$", line.strip()) + if match: + env_vars[match.group(1).upper()] = match.group(2) + return env_vars + + +initial_env = read_env_file("initial_env.txt") +final_env = read_env_file("final_env.txt") + +for key, value in final_env.items(): + if key not in initial_env or initial_env[key] != value: + if key.startswith("_"): + continue + if key.upper() == "PATH": + new_paths = value.split(";") + initial_paths = initial_env.get("PATH", "").split(";") + added_paths = [p for p in new_paths if p not in initial_paths and p] + + if added_paths: + print("Adding paths") + with open(os.environ["GITHUB_PATH"], "a") as f: + for path in added_paths: + print(f"Adding PATH: {path}") + f.write(path + os.linesep) + else: + # Use GITHUB_ENV + with open(os.environ["GITHUB_ENV"], "a") as f: + print(f"Setting {key}={value}\n") + f.write(f"{key}={value}\n") diff --git a/.github/actions/macos-ci-setup/action.yml b/.github/actions/macos-ci-setup/action.yml new file mode 100644 index 0000000000000..e170ccf50a0ac --- /dev/null +++ b/.github/actions/macos-ci-setup/action.yml @@ -0,0 +1,79 @@ +name: "macOS CI pipeline setup steps" +description: "Common setup steps for macOS CI pipelines" + +inputs: + platform_machine: + required: false + type: string + default: "arm64" + python_version: + required: false + type: string + default: "3.11" + node_version: + required: false + type: string + default: "20.x" + java_version: + required: false + type: string + default: "17" + xcode_version: + required: false + type: string + default: "16" + use_cache: + required: false + type: boolean + default: false + +runs: + using: "composite" + steps: + - name: Use Python + uses: actions/setup-python@v5 + with: + python-version: ${{ inputs.python_version }} + + - name: Verify machine architecture + shell: python + run: | + import platform + print(f"Running on {platform.machine()}") + assert platform.machine().lower() == "${{ inputs.platform_machine}}", "This job expects to be run on an ${{ inputs.platform_machine}} machine." + + - name: Use Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ inputs.node_version }} + + - name: Install coreutils and ninja + shell: bash + run: brew install coreutils ninja + + - name: Install Java + uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: ${{ inputs.java_version }} + + - name: Use Xcode ${{ inputs.xcode_version }} + shell: bash + run: | + XCODE_DEVELOPER_DIR="/Applications/Xcode_${{ inputs.xcode_version }}.app/Contents/Developer" + sudo xcode-select --switch "${XCODE_DEVELOPER_DIR}" + + - name: Export GitHub Actions cache environment variables + if: ${{ inputs.use_cache }} + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Install python dependencies + shell: bash + working-directory: ${{ github.workspace }} + run: | + python -m pip install --upgrade pip + python -m pip install -r requirements-dev.txt diff --git a/.github/actions/setup-android-ndk/action.yml b/.github/actions/setup-android-ndk/action.yml new file mode 100644 index 0000000000000..fea9745396e81 --- /dev/null +++ b/.github/actions/setup-android-ndk/action.yml @@ -0,0 +1,98 @@ +# .github/actions/setup-android-ndk/action.yml +name: 'Setup Android NDK' +description: 'Installs and configures a specific version of the Android NDK' +inputs: + ndk-version: + description: 'The version of the Android NDK to install (e.g., 27.2.12479018)' + required: true + default: '27.2.12479018' + android-sdk-root: + description: 'The root directory of the Android SDK' + required: true + default: '/usr/local/lib/android/sdk' + +runs: + using: "composite" # Use a composite action for multiple shell commands + steps: + - name: Install coreutils and ninja + shell: bash + run: sudo apt-get update -y && sudo apt-get install -y coreutils ninja-build + + - name: Install Android NDK + shell: bash + run: | + set -e + "${{ inputs.android-sdk-root }}/cmdline-tools/latest/bin/sdkmanager" --install "ndk;${{ inputs.ndk-version }}" + + NDK_PATH="${{ inputs.android-sdk-root }}/ndk/${{ inputs.ndk-version }}" + if [[ ! -d "${NDK_PATH}" ]]; then + echo "NDK directory is not in expected location: ${NDK_PATH}" + exit 1 + fi + + # Use standard environment variable setting in bash and add to GITHUB_ENV + echo "ANDROID_NDK_HOME=${NDK_PATH}" >> $GITHUB_ENV + echo "ANDROID_NDK_ROOT=${NDK_PATH}" >> $GITHUB_ENV + echo "ANDROID_NDK_HOME: ${NDK_PATH}" + echo "ANDROID_NDK_ROOT: ${NDK_PATH}" + + - name: Check if emulator are installed and add to PATH + shell: bash + run: | + if [[ ":$PATH:" == *":${ANDROID_SDK_ROOT}/emulator:"* ]]; then + echo "${ANDROID_SDK_ROOT}/emulator is in PATH" + else + ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager --install "emulator" + echo "${ANDROID_SDK_ROOT}/emulator" >> $GITHUB_PATH + fi + + - name: Check if platform tools are installed and add to PATH + shell: bash + run: | + if [[ ":$PATH:" == *":${ANDROID_SDK_ROOT}/platform-tools:"* ]]; then + echo "${ANDROID_SDK_ROOT}/platform-tools is in PATH" + else + ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager --install "platform-tools" + echo "${ANDROID_SDK_ROOT}/platform-tools" >> $GITHUB_PATH + fi + ls -R "${ANDROID_SDK_ROOT}/platform-tools" + + - name: Create Android Emulator + shell: bash + env: + ANDROID_AVD_HOME: ${{ runner.temp }}/android-avd + run: | + python3 tools/python/run_android_emulator.py \ + --android-sdk-root "${ANDROID_SDK_ROOT}" \ + --create-avd --system-image "system-images;android-31;default;x86_64" + + - name: List Android AVDs + shell: bash + env: + ANDROID_AVD_HOME: ${{ runner.temp }}/android-avd + run: | + "${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/avdmanager" list avd + + - name: Check emulator.pid does not exist + shell: bash + run: | + if test -f ./emulator.pid; then + echo "Emulator PID file was not expected to exist but does and has pid: `cat ./emulator.pid`" + exit 1 + fi + + - name: Start Android Emulator + shell: bash + env: + ANDROID_AVD_HOME: ${{ runner.temp }}/android-avd + run: | + set -e -x + python3 tools/python/run_android_emulator.py \ + --android-sdk-root "${ANDROID_SDK_ROOT}" \ + --start --emulator-extra-args="-partition-size 2047" \ + --emulator-pid-file ./emulator.pid + echo "Emulator PID: `cat ./emulator.pid`" + + - name: View Android ENVs + shell: bash + run: env | grep ANDROID \ No newline at end of file diff --git a/.github/actions/webgpu-validate-shader-key/action.yml b/.github/actions/webgpu-validate-shader-key/action.yml new file mode 100644 index 0000000000000..86406a2e91877 --- /dev/null +++ b/.github/actions/webgpu-validate-shader-key/action.yml @@ -0,0 +1,29 @@ +name: "WebGPU Validate Shader Key" +description: "Validate if the shader key is consistent for WebGPU shaders." + +inputs: + log_file_path: + required: true + type: string + is_chromium_log: + required: false + type: boolean + default: false + +runs: + using: "composite" + steps: + - name: Validate shader keys (chromium log) + # GitHub Actions treats all inputs as strings even if it's specified as a boolean. + if: ${{ inputs.is_chromium_log == 'true' }} + shell: cmd + run: | + node parse-chromium-debug-log.js < "${{ inputs.log_file_path }}" | node validate-shader-key.js + working-directory: ${{ github.action_path }} + + - name: Validate shader keys (native log) + if: ${{ inputs.is_chromium_log != 'true' }} + shell: cmd + run: | + node validate-shader-key.js < "${{ inputs.log_file_path }}" + working-directory: ${{ github.action_path }} diff --git a/.github/actions/webgpu-validate-shader-key/parse-chromium-debug-log.js b/.github/actions/webgpu-validate-shader-key/parse-chromium-debug-log.js new file mode 100644 index 0000000000000..2342381f03934 --- /dev/null +++ b/.github/actions/webgpu-validate-shader-key/parse-chromium-debug-log.js @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +"use strict"; + +const { EOL } = require("os"); +const readline = require("readline"); + +// This script is used to parse the Chromium debug log and extract the raw log data. + +async function processChromiumDebugLog() { + const rl = readline.createInterface({ + input: process.stdin, + crlfDelay: Infinity, + }); + + for await (const line of rl) { + const result = + /^\[.+INFO:CONSOLE\(\d+\)]\ "(?.+)",\ source:\ [^"]+?\(\d+\)$/.exec( + line + ); + if (!result) { + continue; + } + const rawLogData = result.groups.raw_log_data; + process.stdout.write(`${rawLogData}${EOL}`); + } +} + +processChromiumDebugLog(); diff --git a/.github/actions/webgpu-validate-shader-key/validate-shader-key.js b/.github/actions/webgpu-validate-shader-key/validate-shader-key.js new file mode 100644 index 0000000000000..aae689c17552a --- /dev/null +++ b/.github/actions/webgpu-validate-shader-key/validate-shader-key.js @@ -0,0 +1,122 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +"use strict"; + +const { EOL } = require("os"); +const readline = require("readline"); + +// This script is used to parse the raw log data and check if there are inconsistent shader. +// When the shader key is the same, the shader code should be the same. + +const shaderMap = new Map(); + +const regexStartingProgram = + /onnxruntime::webgpu::WebGpuContext::Run.+Starting program \"(?.+)\"/; +const regexShaderStart = + /^===\ WebGPU\ Shader\ code\ \[.+?(Key=\"(?.+)\")?]\ Start\ ===$/; +const regexShaderEnd = + /^===\ WebGPU\ Shader\ code\ \[.+?(Key=\"(?.+)\")?]\ End\ ===$/; + +async function processVerboseLog() { + const rl = readline.createInterface({ + input: process.stdin, + crlfDelay: Infinity, + }); + + let lastProgramKey = null; + let currentShaderKey = null; + let currentShaderCode = null; + + for await (const line of rl) { + const startingProgram = regexStartingProgram.exec(line); + if (startingProgram) { + lastProgramKey = startingProgram.groups.key; + continue; + } + + const resultStart = regexShaderStart.exec(line); + if (resultStart) { + if (currentShaderKey) { + throw new Error( + `Found incomplete shader code for key "${currentShaderKey}".` + ); + } + + const key = resultStart.groups.key ?? lastProgramKey; + if (!key) { + throw new Error( + 'No shader key is found in the log. Please use debug build or enable verbose logging in session options in release build.' + ); + } + if (lastProgramKey && key !== lastProgramKey) { + throw new Error( + `Found incorrect shader key from log. Expected "${lastProgramKey}", but got "${key}".` + ); + } + currentShaderKey = key; + currentShaderCode = ""; + continue; + } + + const resultEnd = regexShaderEnd.exec(line); + if (resultEnd) { + if (!currentShaderKey) { + throw new Error( + `Found unexpected shader end for key "${resultEnd.groups.key}".` + ); + } + + const key = resultEnd.groups.key ?? lastProgramKey; + if (!key) { + throw new Error( + 'No shader key is found in the log. Please use debug build or enable verbose logging in session options in release build.' + ); + } + if (lastProgramKey && key !== lastProgramKey) { + throw new Error( + `Found incorrect shader key from log. Expected "${lastProgramKey}", but got "${key}".` + ); + } + + if (shaderMap.has(currentShaderKey)) { + if (shaderMap.get(currentShaderKey) !== currentShaderCode) { + throw new Error(`Found inconsistent shader code for key "${currentShaderKey}". +=== Previous Shader Start === +${shaderMap.get(currentShaderKey)} +=== Previous Shader End === + +=== Current Shader Start === +${currentShaderCode} +=== Current Shader End ===`); + } + } else { + shaderMap.set(currentShaderKey, currentShaderCode); + } + + currentShaderKey = null; + currentShaderCode = null; + continue; + } + + if (currentShaderKey) { + currentShaderCode += line + EOL; + } + } + + if (currentShaderKey) { + throw new Error( + `Found incomplete shader code for key "${currentShaderKey}".` + ); + } + + if (shaderMap.size === 0) { + throw new Error("No shader code found."); + } + + console.log( + `All shader code is consistent. Total ${shaderMap.size} shader keys found.` + ); +} + +processVerboseLog(); diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml new file mode 100644 index 0000000000000..a456d8b036e7b --- /dev/null +++ b/.github/workflows/android.yml @@ -0,0 +1,157 @@ +name: Android CI +# This workflow is used to build and test on Android Emulator on Linux + +on: + push: + branches: + - main + - rel-* + pull_request: + branches: + - main + - rel-* + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name == 'workflow_dispatch' }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + android_nnapi_ep: + runs-on: ["self-hosted", "1ES.Pool=onnxruntime-github-Ubuntu2204-AMD-CPU"] + steps: + - uses: actions/checkout@v4 + + - name: Use jdk 17 + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + architecture: x64 + + + - uses: microsoft/onnxruntime-github-actions/setup-build-tools@v0.0.5 + with: + vcpkg-version: '2025.03.19' + vcpkg-hash: '17e96169cd3f266c4716fcdc1bb728e6a64f103941ece463a2834d50694eba4fb48f30135503fd466402afa139abc847ef630733c442595d1c34979f261b0114' + cmake-version: '3.31.6' + cmake-hash: '42395e20b10a8e9ef3e33014f9a4eed08d46ab952e02d2c1bbc8f6133eca0d7719fb75680f9bbff6552f20fcd1b73d86860f7f39388d631f98fb6f622b37cf04' + add-cmake-to-path: 'true' + disable-terrapin: 'true' + + - name: Setup Android NDK + uses: ./.github/actions/setup-android-ndk + with: + ndk-version: 28.0.13004108 + + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: NNAPI EP, Build, Test on Android Emulator + run: >- + python3 tools/ci_build/build.py + --enable_lto + --android + --build_dir build_nnapi + --android_sdk_path "$ANDROID_HOME" + --android_ndk_path "$ANDROID_NDK_HOME" + --android_abi=x86_64 + --android_api=29 + --skip_submodule_sync + --parallel --use_vcpkg --use_vcpkg_ms_internal_asset_cache + --use_nnapi + --build_shared_lib + --cmake_generator=Ninja + --build_java + shell: bash + + + - name: Build Minimal ORT with NNAPI and run tests + run: tools/ci_build/github/linux/ort_minimal/nnapi_minimal_build_minimal_ort_and_run_tests.sh "$(pwd)" + shell: bash + + - name: Install psutil for emulator shutdown by run_android_emulator.py + if: always() + run: python3 -m pip install psutil + shell: bash + + - name: Stop Android Emulator + if: always() + run: | + env | grep ANDROID + if test -f ${{ github.workspace }}/emulator.pid; then + echo "Emulator PID:"`cat ${{ github.workspace }}/emulator.pid` + python3 tools/python/run_android_emulator.py \ + --android-sdk-root "${ANDROID_SDK_ROOT}" \ + --stop \ + --emulator-pid-file ${{ github.workspace }}/emulator.pid + rm ${{ github.workspace }}/emulator.pid + else + echo "Emulator PID file was expected to exist but does not." + fi + shell: bash + + android_cpu_ep: + name: Android CI Pipeline + runs-on: ["self-hosted", "1ES.Pool=onnxruntime-github-Ubuntu2204-AMD-CPU"] + steps: + - uses: actions/checkout@v4 + + - name: Use jdk 17 + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + architecture: x64 + + - name: Setup Android NDK + uses: ./.github/actions/setup-android-ndk + with: + ndk-version: 28.0.13004108 + + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: CPU EP, Build and Test + run: >- + python3 tools/ci_build/build.py + --enable_lto + --android + --build_dir build + --android_sdk_path $ANDROID_HOME + --android_ndk_path $ANDROID_NDK_HOME + --android_abi=x86_64 + --android_api=30 + --skip_submodule_sync + --parallel --use_vcpkg --use_vcpkg_ms_internal_asset_cache + --cmake_generator=Ninja + --build_java + shell: bash + + - name: Install psutil for emulator shutdown by run_android_emulator.py + if: always() + run: python3 -m pip install psutil + shell: bash + + - name: Stop Android Emulator + if: always() + run: | + if test -f ${{ github.workspace }}/emulator.pid; then + echo "Emulator PID:"`cat ${{ github.workspace }}/emulator.pid` + python3 tools/python/run_android_emulator.py \ + --android-sdk-root "${ANDROID_SDK_ROOT}" \ + --stop \ + --emulator-pid-file ${{ github.workspace }}/emulator.pid + rm ${{ github.workspace }}/emulator.pid + else + echo "Emulator PID file was expected to exist but does not." + fi + shell: bash diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index cf3bc598d02bb..9adae8c0d6854 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -3,7 +3,11 @@ # This workflow was copied from the link above. name: "Validate Gradle Wrapper" -on: [push, pull_request] +on: + push: + branches: [ main, 'rel-*'] + pull_request: + branches: [ main, 'rel-*'] jobs: validation: diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml new file mode 100644 index 0000000000000..2c51bf0ce476f --- /dev/null +++ b/.github/workflows/ios.yml @@ -0,0 +1,64 @@ +name: iOS_CI_on_Mac + +on: + push: + branches: + - main + - rel-* + pull_request: + branches: + - main + - rel-* + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + iOS_CI_on_Mac: + runs-on: macos-14 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: false + - name: Use Xcode ${{ env.XCODE_VERSION }} + shell: bash + run: | + set -e -x + XCODE_DEVELOPER_DIR="/Applications/Xcode_${{ env.XCODE_VERSION }}.app/Contents/Developer" + sudo xcode-select --switch "${XCODE_DEVELOPER_DIR}" + + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: (CPU, CoreML, XNNPACK EPs) Build onnxruntime for iOS x86_64 and run tests using simulator + shell: bash + run: | + python3 ${{ github.workspace }}/tools/ci_build/build.py \ + --skip_submodule_sync \ + --build_dir ${{ github.workspace }}/iOS \ + --build_shared_lib \ + --use_coreml \ + --use_xnnpack \ + --ios \ + --apple_sysroot iphonesimulator \ + --osx_arch x86_64 \ + --apple_deploy_target=15.1 \ + --use_xcode \ + --config RelWithDebInfo \ + --build_apple_framework \ + --parallel \ + --use_binskim_compliant_compile_flags + env: + ORT_GET_SIMULATOR_DEVICE_INFO_REQUESTED_RUNTIME_VERSION: ${{ env.IOS_SIMULATOR_RUNTIME_VERSION }} + + timeout-minutes: 150 + env: + XCODE_VERSION: 15.3.0 + IOS_SIMULATOR_RUNTIME_VERSION: 17.4 \ No newline at end of file diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 8d966d358de01..21baab0fd191c 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -26,7 +26,7 @@ jobs: level: info filter_mode: diff_context - name: shellcheck # Static check shell scripts - uses: reviewdog/action-shellcheck@v1 + uses: reviewdog/action-shellcheck@v1.30.0 with: github_token: ${{ secrets.github_token }} reporter: github-pr-check diff --git a/.github/workflows/linux-dnnl.yml b/.github/workflows/linux-dnnl.yml new file mode 100644 index 0000000000000..948de1889bf64 --- /dev/null +++ b/.github/workflows/linux-dnnl.yml @@ -0,0 +1,38 @@ +# This workflow builds and tests the ONNX Runtime for Linux for DNNL EP +# It leverages a reusable workflow (`reusable_linux_build.yml`) to handle the core build and test logic +# within Docker containers, ensuring a consistent environment. +# This file is very similar to linux_ci.yml, but much simpler + + +name: Linux DNNL CI + +on: + push: + branches: [ main, 'rel-*'] + pull_request: + branches: [ main, 'rel-*'] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + packages: write + attestations: write + id-token: write + +jobs: + build-linux-x64-release-dnnl: + name: Build Linux x64 Release (DNNL EP) + uses: ./.github/workflows/reusable_linux_build.yml + with: + pool_name: "onnxruntime-github-Ubuntu2204-AMD-CPU" + build_config: Release + architecture: x64 + dockerfile_path: tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cpu + docker_image_repo: onnxruntimecpubuildpythonx64 + extra_build_flags: '--use_binskim_compliant_compile_flags --build_wheel --build_nuget --use_dnnl' + python_path_prefix: 'PATH=/opt/python/cp310-cp310/bin:$PATH' + secrets: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/linux-wasm-ci-build-and-test-workflow.yml b/.github/workflows/linux-wasm-ci-build-and-test-workflow.yml new file mode 100644 index 0000000000000..b0ba518242aa8 --- /dev/null +++ b/.github/workflows/linux-wasm-ci-build-and-test-workflow.yml @@ -0,0 +1,143 @@ +name: "Linux WASM CI Reusable Workflow for build and test" +description: "This is a reusable workflow for Linux WASM CI pipelines to build and test" + +on: + workflow_call: + inputs: + build_config: + required: true + type: string + extra_build_args: + required: false + type: string + default: "" + skip_publish: + required: false + type: boolean + default: false + build_jsep: + required: false + type: boolean + default: false + build_webgpu: + required: false + type: boolean + default: false + +jobs: + build-wasm: + runs-on: ["self-hosted", "1ES.Pool=onnxruntime-github-Ubuntu2204-AMD-CPU"] + env: + buildArch: x64 + common_build_args: --parallel --use_vcpkg --use_vcpkg_ms_internal_asset_cache --config ${{ inputs.build_config }} --skip_submodule_sync --build_wasm --enable_wasm_simd --enable_wasm_threads ${{ inputs.extra_build_args }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + architecture: ${{ env.buildArch }} + - uses: microsoft/onnxruntime-github-actions/setup-build-tools@v0.0.5 + with: + vcpkg-version: '2025.03.19' + vcpkg-hash: '17e96169cd3f266c4716fcdc1bb728e6a64f103941ece463a2834d50694eba4fb48f30135503fd466402afa139abc847ef630733c442595d1c34979f261b0114' + cmake-version: '3.31.6' + cmake-hash: '42395e20b10a8e9ef3e33014f9a4eed08d46ab952e02d2c1bbc8f6133eca0d7719fb75680f9bbff6552f20fcd1b73d86860f7f39388d631f98fb6f622b37cf04' + add-cmake-to-path: 'true' + disable-terrapin: 'true' + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Install EMSDK + run: | + set -ex + cd ${{ github.workspace }}/cmake/external/emsdk + ./emsdk install 4.0.4 + ./emsdk activate 4.0.4 + + - name: Build and test (browser) (simd + threads) + run: | + set -e -x + source ${{ github.workspace }}/cmake/external/emsdk/emsdk_env.sh + cd '${{ github.workspace }}' + python ./tools/ci_build/build.py \ + ${{ env.common_build_args }} \ + --build_dir ${{ github.workspace }}/build/wasm_inferencing \ + --wasm_run_tests_in_browser + + - name: Build (simd + threads + JSEP) + if: ${{ inputs.build_jsep == true }} + run: | + set -e -x + source ${{ github.workspace }}/cmake/external/emsdk/emsdk_env.sh + cd '${{ github.workspace }}' + python ./tools/ci_build/build.py \ + ${{ env.common_build_args }} \ + --build_dir ${{ github.workspace }}/build/wasm_inferencing_jsep \ + --use_jsep \ + --use_webnn \ + --target onnxruntime_webassembly \ + --skip_tests + + - name: Build (simd + threads + WebGPU experimental) + if: ${{ inputs.build_webgpu == true }} + run: | + set -e -x + source ${{ github.workspace }}/cmake/external/emsdk/emsdk_env.sh + cd '${{ github.workspace }}' + python ./tools/ci_build/build.py \ + ${{ env.common_build_args }} \ + --build_dir ${{ github.workspace }}/build/wasm_inferencing_webgpu \ + --use_webgpu \ + --use_jsep \ + --use_webnn \ + --target onnxruntime_webassembly \ + --skip_tests + + - name: Create Artifacts + if: ${{ inputs.skip_publish != true }} + run: | + mkdir -p ${{ github.workspace }}/artifacts/wasm/ + cp ${{ github.workspace }}/build/wasm_inferencing/${{ inputs.build_config }}/ort-wasm-simd-threaded.wasm ${{ github.workspace }}/artifacts/wasm/ + cp ${{ github.workspace }}/build/wasm_inferencing/${{ inputs.build_config }}/ort-wasm-simd-threaded.mjs ${{ github.workspace }}/artifacts/wasm/ + if [ -d ${{ github.workspace }}/build/wasm_inferencing_jsep ]; then + cp ${{ github.workspace }}/build/wasm_inferencing_jsep/${{ inputs.build_config }}/ort-wasm-simd-threaded.jsep.wasm ${{ github.workspace }}/artifacts/wasm/ + cp ${{ github.workspace }}/build/wasm_inferencing_jsep/${{ inputs.build_config }}/ort-wasm-simd-threaded.jsep.mjs ${{ github.workspace }}/artifacts/wasm/ + fi + + - name: Create WebGPU Artifacts + if: ${{ inputs.skip_publish != true && inputs.build_webgpu == true }} + run: | + mkdir -p ${{ github.workspace }}/artifacts/wasm_webgpu/ + cp ${{ github.workspace }}/build/wasm_inferencing_webgpu/${{ inputs.build_config }}/ort-wasm-simd-threaded.jsep.wasm ${{ github.workspace }}/artifacts/wasm_webgpu/ + cp ${{ github.workspace }}/build/wasm_inferencing_webgpu/${{ inputs.build_config }}/ort-wasm-simd-threaded.jsep.mjs ${{ github.workspace }}/artifacts/wasm_webgpu/ + + - name: Upload WASM artifacts + if: ${{ inputs.skip_publish != true }} + uses: actions/upload-artifact@v4 + with: + name: ${{ inputs.build_config }}_wasm + path: ${{ github.workspace }}/artifacts/wasm + + - name: Upload WebGPU artifacts + if: ${{ inputs.skip_publish != true && inputs.build_webgpu == true }} + uses: actions/upload-artifact@v4 + with: + name: ${{ inputs.build_config }}_wasm_webgpu + path: ${{ github.workspace }}/artifacts/wasm_webgpu + + - name: Publish test results + if: ${{ always() && inputs.build_config == 'Debug' }} + uses: actions/upload-artifact@v4 + with: + name: test-results + path: ${{ github.workspace }}/build/**/*.results.xml diff --git a/.github/workflows/linux_ci.yml b/.github/workflows/linux_ci.yml new file mode 100644 index 0000000000000..daa985212552a --- /dev/null +++ b/.github/workflows/linux_ci.yml @@ -0,0 +1,109 @@ +# This workflow builds and tests the ONNX Runtime for Linux on multiple architectures and configurations. +# It leverages a reusable workflow (`reusable_linux_build.yml`) to handle the core build and test logic +# within Docker containers, ensuring a consistent environment. +# +# The workflow consists of five parallel jobs targeting different combinations: +# - build-linux-x64-debug: Builds/tests Debug config on Linux x64 (AMD CPU pool), enables AddressSanitizer. +# - build-linux-x64-release: Builds/tests Release config on Linux x64 (AMD CPU pool), includes wheel/nuget/benchmark flags. +# - orttraining-linux-ci-pipeline: Builds/tests Release config with Training enabled (--enable_training) on Linux x64 (AMD CPU pool). +# - build-linux-arm64-debug: Builds/tests Debug config on Linux arm64 (ARM CPU pool); ASan is disabled due to excessive runtime. Includes wheel build. +# - build-linux-arm64-release: Builds/tests Release config on Linux arm64 (ARM CPU pool), includes wheel/benchmark flags. +# +# Each job calls the reusable workflow, passing specific parameters: +# - target architecture (x64 or arm64) +# - build configuration (Debug or Release) +# - runner pool name +# - path to the appropriate Dockerfile +# - Docker image name for caching/use +# - configuration-specific build flags (e.g., --enable_address_sanitizer, --enable_training, --build_wheel) + +name: Linux CI + +on: + push: + branches: [ main, 'rel-*'] + pull_request: + branches: [ main, 'rel-*'] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + packages: write + attestations: write + id-token: write + +jobs: + # --- x64 Builds --- + build-linux-x64-debug: + name: Build Linux x64 Debug (ASan) + uses: ./.github/workflows/reusable_linux_build.yml + with: + pool_name: "onnxruntime-github-Ubuntu2204-AMD-CPU" + build_config: Debug + architecture: x64 + dockerfile_path: tools/ci_build/github/linux/docker/inference/x86_64/default/cpu/Dockerfile + docker_image_repo: onnxruntimecpubuildcix64 + extra_build_flags: '--enable_address_sanitizer' + # python_path_prefix: '' # Default empty string is fine, no prefix needed + secrets: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + build-linux-x64-release: + name: Build Linux x64 Release + uses: ./.github/workflows/reusable_linux_build.yml + with: + pool_name: "onnxruntime-github-Ubuntu2204-AMD-CPU" + build_config: Release + architecture: x64 + dockerfile_path: tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cpu + docker_image_repo: onnxruntimecpubuildpythonx64 + extra_build_flags: '--use_binskim_compliant_compile_flags --build_wheel --build_nuget --enable_transformers_tool_test --cmake_extra_defines onnxruntime_BUILD_BENCHMARKS=ON' + python_path_prefix: 'PATH=/opt/python/cp310-cp310/bin:$PATH' # $ needs escaping in single quotes + secrets: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + orttraining-linux-ci-pipeline: + name: Build Linux x64 Release with training + uses: ./.github/workflows/reusable_linux_build.yml + with: + pool_name: "onnxruntime-github-Ubuntu2204-AMD-CPU" + build_config: Release + architecture: x64 + dockerfile_path: tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cpu + docker_image_repo: onnxruntimecpubuildpythonx64 # Shares image with standard x64 release + extra_build_flags: '--enable_training --use_binskim_compliant_compile_flags --build_wheel --build_nuget --enable_transformers_tool_test --cmake_extra_defines onnxruntime_BUILD_BENCHMARKS=ON' + python_path_prefix: 'PATH=/opt/python/cp310-cp310/bin:$PATH' # $ needs escaping in single quotes + secrets: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # --- arm64 Builds --- + build-linux-arm64-debug: + name: Build Linux arm64 Debug + uses: ./.github/workflows/reusable_linux_build.yml + with: + pool_name: "onnxruntime-github-Ubuntu2204-ARM-CPU" + build_config: Debug + architecture: arm64 + dockerfile_path: tools/ci_build/github/linux/docker/inference/aarch64/default/cpu/Dockerfile + docker_image_repo: onnxruntimecpubuildciaarch64 + # ASan disabled due to excessive runtime (>4hr). Includes wheel build for basic checks. + extra_build_flags: '--use_binskim_compliant_compile_flags --build_shared_lib' + secrets: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + build-linux-arm64-release: + name: Build Linux arm64 Release + uses: ./.github/workflows/reusable_linux_build.yml + with: + pool_name: "onnxruntime-github-Ubuntu2204-ARM-CPU" + build_config: Release + architecture: arm64 + dockerfile_path: tools/ci_build/github/linux/docker/inference/aarch64/python/cpu/Dockerfile + docker_image_repo: onnxruntimecpubuildpythonaarch64 + extra_build_flags: '--use_binskim_compliant_compile_flags --build_wheel --cmake_extra_defines onnxruntime_BUILD_BENCHMARKS=ON' + python_path_prefix: 'PATH=/opt/python/cp310-cp310/bin:$PATH' # $ needs escaping in single quotes + secrets: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/linux_cuda_ci.yml b/.github/workflows/linux_cuda_ci.yml new file mode 100644 index 0000000000000..66369f43f9aea --- /dev/null +++ b/.github/workflows/linux_cuda_ci.yml @@ -0,0 +1,102 @@ +name: Linux CUDA CI + +on: + push: + branches: [ main, 'rel-*'] + pull_request: + branches: [ main, 'rel-*'] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + packages: write + attestations: write + id-token: write + +jobs: + build-linux-cuda-x64-release: + name: Build Linux CUDA x64 Release + # This job runs on a CPU node using the reusable build workflow + uses: ./.github/workflows/reusable_linux_build.yml + with: + pool_name: "onnxruntime-github-Ubuntu2204-AMD-CPU" # Build pool + build_config: Release + architecture: x64 + dockerfile_path: tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda + docker_build_args: '--build-arg BASEIMAGE=onnxruntimebuildcache.azurecr.io/internal/azureml/onnxruntime/build/cuda12_x64_ubi8_gcc12:20250124.1' + docker_image_repo: onnxruntimecuda12manylinuxbuild + extra_build_flags: '--use_binskim_compliant_compile_flags --build_wheel --cuda_version=12.2 --cuda_home=/usr/local/cuda-12.2 --cudnn_home=/usr/local/cuda-12.2 --enable_cuda_profiling --build_java --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=80 onnxruntime_BUILD_UNIT_TESTS=ON onnxruntime_ENABLE_CUDA_EP_INTERNAL_TESTS=ON' + python_path_prefix: 'PATH=/opt/python/cp310-cp310/bin:$PATH' + run_tests: false # <<< Do not run tests in this job + upload_build_output: true # <<< Upload the build/Release directory + execution_providers: 'cuda' + secrets: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Pass token for reusable workflow needs (e.g., docker build action) + + test-linux-cuda-x64-release: + name: Test Linux CUDA x64 Release + needs: build-linux-cuda-x64-release + runs-on: + - self-hosted + - "1ES.Pool=Onnxruntime-github-Linux-GPU-A100-WUS3" + permissions: + contents: read + packages: read + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - uses: microsoft/onnxruntime-github-actions/build-docker-image@v0.0.5 + id: build_docker_image_step + with: + dockerfile: ${{ github.workspace }}/tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda + image-name: ghcr.io/microsoft/onnxruntime/onnxruntimecuda12manylinuxbuild + build-args: '--build-arg BASEIMAGE=onnxruntimebuildcache.azurecr.io/internal/azureml/onnxruntime/build/cuda12_x64_ubi8_gcc12:20250124.1' + push: true + azure-container-registry-name: onnxruntimebuildcache + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Pass token to action + + # --- Download Build Artifact to Runner Temp Directory --- + - name: Download Build Artifact + uses: actions/download-artifact@v4 + with: + name: build-output-x64-Release # Must match the upload name + path: ${{ runner.temp }}/Release # Download contents into temp dir structure + + # --- Restore Permissions in the Temp Directory --- + - name: Restore Executable Permissions + if: success() # Only run if download succeeded + working-directory: ${{ runner.temp }}/Release + run: | + if [ -f perms.txt ]; then + echo "Restoring executable permissions in ${{ runner.temp }}/Release ..." + while IFS= read -r file; do + # Check relative path existence within the current directory + if [ -f "$file" ]; then + chmod +x "$file" + else + echo "Warning: File '$file' listed in perms.txt not found." + fi + done < perms.txt + echo "Permissions restored." + else + echo "Warning: perms.txt not found in artifact." + fi + + # --- Run Tests using the downloaded build --- + # The run-build-script-in-docker action mounts ${{ runner.temp }} to /onnxruntime_src/build + # So build.py --build_dir build/Release inside the container correctly finds the artifacts. + - name: Test ONNX Runtime + id: test_step + uses: microsoft/onnxruntime-github-actions/run-build-script-in-docker@v0.0.5 + with: + docker_image: ${{ steps.build_docker_image_step.outputs.full-image-name }} + build_config: Release + mode: 'test' # Set mode to test + execution_providers: 'cuda' + extra_build_flags: '--use_binskim_compliant_compile_flags --cuda_version=12.2 --cuda_home=/usr/local/cuda-12.2 --cudnn_home=/usr/local/cuda-12.2 --enable_cuda_profiling --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=80 onnxruntime_BUILD_UNIT_TESTS=ON onnxruntime_ENABLE_CUDA_EP_INTERNAL_TESTS=ON' + python_path_prefix: 'PATH=/opt/python/cp310-cp310/bin:$PATH' diff --git a/.github/workflows/linux_tensorrt_ci.yml b/.github/workflows/linux_tensorrt_ci.yml new file mode 100644 index 0000000000000..ca4c825a95edb --- /dev/null +++ b/.github/workflows/linux_tensorrt_ci.yml @@ -0,0 +1,104 @@ +name: Linux TensorRT CI + +on: + push: + branches: [ main, 'rel-*'] + pull_request: + branches: [ main, 'rel-*'] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + packages: write + attestations: write + id-token: write + +jobs: + build-linux-TensorRT-x64-release: + name: Build Linux TensorRT x64 Release + # This job runs on a CPU node using the reusable build workflow + uses: ./.github/workflows/reusable_linux_build.yml + with: + pool_name: "onnxruntime-github-Ubuntu2204-AMD-CPU" # Build pool + build_config: Release + architecture: x64 + dockerfile_path: tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda + docker_build_args: '--build-arg BASEIMAGE=onnxruntimebuildcache.azurecr.io/internal/azureml/onnxruntime/build/cuda12_x64_ubi8_gcc12:20250124.1 --build-arg TRT_VERSION=10.9.0.34-1.cuda12.8 --network=host' + docker_image_repo: onnxruntimetensorrt86gpubuild + extra_build_flags: '--use_binskim_compliant_compile_flags --build_wheel --cuda_version=12.2 --cuda_home=/usr/local/cuda-12.2 --cudnn_home=/usr/local/cuda-12.2 --use_tensorrt --tensorrt_home /usr --build_java --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=80 onnxruntime_BUILD_UNIT_TESTS=ON onnxruntime_ENABLE_CUDA_EP_INTERNAL_TESTS=ON' + python_path_prefix: 'PATH=/opt/python/cp310-cp310/bin:$PATH' + run_tests: false # <<< Do not run tests in this job + upload_build_output: true # <<< Upload the build/Release directory + execution_providers: 'cuda tensorrt' + secrets: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Pass token for reusable workflow needs (e.g., docker build action) + + test-linux-TensorRT-x64-release: + name: Test Linux TensorRT x64 Release + needs: build-linux-TensorRT-x64-release + runs-on: + - self-hosted + - "1ES.Pool=Onnxruntime-github-Linux-GPU-A100-WUS3" + permissions: + contents: read + packages: read + steps: + - name: Checkout code + uses: actions/checkout@v4 + + # --- Build the Docker image needed for testing --- + - name: Build Docker Image for Testing + uses: microsoft/onnxruntime-github-actions/build-docker-image@v0.0.5 + id: build_docker_image_step + with: + dockerfile: ${{ github.workspace }}/tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda + image-name: ghcr.io/microsoft/onnxruntime/onnxruntimetensorrt86gpubuild + build-args: '--build-arg BASEIMAGE=onnxruntimebuildcache.azurecr.io/internal/azureml/onnxruntime/build/cuda12_x64_ubi8_gcc12:20250124.1 --build-arg TRT_VERSION=10.9.0.34-1.cuda12.8 --network=host' + push: true + azure-container-registry-name: onnxruntimebuildcache + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Pass token to action + + # --- Download Build Artifact to Runner Temp Directory --- + - name: Download Build Artifact + uses: actions/download-artifact@v4 + with: + name: build-output-x64-Release # Must match the upload name + path: ${{ runner.temp }}/Release # Download contents into temp dir structure + + # --- Restore Permissions in the Temp Directory --- + - name: Restore Executable Permissions + if: success() # Only run if download succeeded + working-directory: ${{ runner.temp }}/Release + run: | + if [ -f perms.txt ]; then + echo "Restoring executable permissions in ${{ runner.temp }}/Release ..." + while IFS= read -r file; do + # Check relative path existence within the current directory + if [ -f "$file" ]; then + chmod +x "$file" + else + echo "Warning: File '$file' listed in perms.txt not found." + fi + done < perms.txt + echo "Permissions restored." + else + echo "Warning: perms.txt not found in artifact." + fi + + # --- Run Tests using the downloaded build --- + # The run-build-script-in-docker action mounts ${{ runner.temp }} to /onnxruntime_src/build + # So build.py --build_dir build/Release inside the container correctly finds the artifacts. + - name: Test ONNX Runtime + id: test_step + uses: microsoft/onnxruntime-github-actions/run-build-script-in-docker@v0.0.5 + with: + docker_image: ${{ steps.build_docker_image_step.outputs.full-image-name }} + build_config: Release + mode: 'test' # Set mode to test + execution_providers: 'cuda tensorrt' + extra_build_flags: '--use_binskim_compliant_compile_flags --build_wheel --cuda_version=12.2 --cuda_home=/usr/local/cuda-12.2 --cudnn_home=/usr/local/cuda-12.2 --use_tensorrt --tensorrt_home /usr --build_java --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=80 onnxruntime_BUILD_UNIT_TESTS=ON onnxruntime_ENABLE_CUDA_EP_INTERNAL_TESTS=ON' + python_path_prefix: 'PATH=/opt/python/cp310-cp310/bin:$PATH' diff --git a/.github/workflows/linux_training.yml b/.github/workflows/linux_training.yml deleted file mode 100644 index d382cdf476283..0000000000000 --- a/.github/workflows/linux_training.yml +++ /dev/null @@ -1,55 +0,0 @@ -name: orttraining-linux-ci-pipeline -on: - push: - branches: - - main - - rel-* - pull_request: - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - orttraining-linux-ci-pipeline: - runs-on: ["self-hosted", "1ES.Pool=onnxruntime-github-Ubuntu2204-AMD-CPU"] - permissions: - actions: read - contents: read - security-events: write - steps: - - uses: actions/checkout@v4 - - run: | - python3 -m pip install --user -r tools/ci_build/github/linux/python/requirements.txt - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - config-file: ./.github/codeql/codeql-config.yml - languages: 'cpp' - - run: | - set -e -x - rm -rf build - python3 tools/ci_build/build.py --build_dir build --config Release --enable_training --skip_submodule_sync --parallel --update --build - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 - with: - category: "/language:cpp" - output: sarif-results - upload: failure-only - - - name: filter-sarif - uses: advanced-security/filter-sarif@v1 - with: - patterns: | - +**/*.cc - +**/*.h - -tests/**/*.* - -build/**/*.* - input: sarif-results/cpp.sarif - output: sarif-results/cpp.sarif - - - name: Upload SARIF - uses: github/codeql-action/upload-sarif@v3 - with: - sarif_file: sarif-results/cpp.sarif \ No newline at end of file diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml index 3218afe11edfd..8fcc53bbd9991 100644 --- a/.github/workflows/mac.yml +++ b/.github/workflows/mac.yml @@ -1,14 +1,14 @@ -name: Mac_CI +name: "MacOS CI Pipeline" on: push: branches: - - main - - rel-* + - main + - rel-* pull_request: branches: - - main - - rel-* + - main + - rel-* workflow_dispatch: concurrency: @@ -19,48 +19,37 @@ env: python_version: 3.11 jobs: - ARM64-Xcode16: - runs-on: macos-15 - - env: - xcode_version: 16 - - timeout-minutes: 60 - - steps: - - uses: actions/setup-python@v5 - with: - python-version: ${{ env.python_version }} - - - name: Verify ARM64 machine - shell: python - run: | - import platform - assert platform.machine() == "arm64", "This job expects to be run on an ARM64 machine." - - - name: Use Xcode ${{ env.xcode_version }} - shell: bash - run: | - XCODE_DEVELOPER_DIR="/Applications/Xcode_${{ env.xcode_version }}.app/Contents/Developer" - sudo xcode-select --switch "${XCODE_DEVELOPER_DIR}" - - - uses: actions/checkout@v4 - - - name: Build and test - shell: bash - run: | - python ./tools/ci_build/build.py \ - --build_dir ./build \ - --update \ - --build --parallel \ - --test \ - --build_shared_lib \ - --build_objc \ - --use_coreml \ - --use_xnnpack \ - --use_binskim_compliant_compile_flags - - ARM64-Xcode16-targeting-iphonesimulator: + cpu: + uses: ./.github/workflows/macos-ci-build-and-test-workflow.yml + with: + # Only build arm64 for CPU + matrix_exclude: >- + [ + {"platform_machine": "x86_64"} + ] + + coreml: + uses: ./.github/workflows/macos-ci-build-and-test-workflow.yml + with: + use_coreml: true + + xnnpack: + uses: ./.github/workflows/macos-ci-build-and-test-workflow.yml + with: + use_xnnpack: true + # only build arm64/Debug for XNNPack + matrix_exclude: >- + [ + {"platform_machine": "x86_64"}, + {"platform_machine": "arm64", "build_config": "Release"} + ] + + webgpu: + uses: ./.github/workflows/macos-ci-build-and-test-workflow.yml + with: + use_webgpu: true + + iphone_simulator: runs-on: macos-15 env: @@ -70,44 +59,37 @@ jobs: matrix: target_arch: [x86_64, arm64] - timeout-minutes: 60 + timeout-minutes: 90 steps: - - uses: actions/setup-python@v5 - with: - python-version: ${{ env.python_version }} - - - name: Verify ARM64 machine - shell: python - run: | - import platform - assert platform.machine() == "arm64", "This job expects to be run on an ARM64 machine." - - - name: Use Xcode ${{ env.xcode_version }} - shell: bash - run: | - XCODE_DEVELOPER_DIR="/Applications/Xcode_${{ env.xcode_version }}.app/Contents/Developer" - sudo xcode-select --switch "${XCODE_DEVELOPER_DIR}" - - - uses: actions/checkout@v4 - - - name: Build for iphonesimulator ${{ matrix.target_arch }} - shell: bash - run: | - python ./tools/ci_build/build.py \ - --build_dir ./build \ - --update \ - --build --parallel \ - --test \ - --build_apple_framework \ - --use_xcode \ - --use_coreml \ - --use_xnnpack \ - --use_binskim_compliant_compile_flags \ - --ios \ - --apple_deploy_target=15.1 \ - --apple_sysroot=iphonesimulator \ - --osx_arch=${{ matrix.target_arch }} + - name: Checkout code + uses: actions/checkout@v4 + + - name: macOS CI pipeline prepare steps + uses: ./.github/actions/macos-ci-setup + with: + platform_machine: "arm64" + python_version: ${{ env.python_version }} + xcode_version: ${{ env.xcode_version }} + use_cache: false + + - name: Build for iphonesimulator ${{ matrix.target_arch }} + shell: bash + run: | + python ./tools/ci_build/build.py \ + --build_dir ./build \ + --update \ + --build --parallel \ + --test \ + --build_apple_framework \ + --use_xcode \ + --use_coreml \ + --use_xnnpack \ + --use_binskim_compliant_compile_flags \ + --ios \ + --apple_deploy_target=15.1 \ + --apple_sysroot=iphonesimulator \ + --osx_arch=${{ matrix.target_arch }} Objective-C-StaticAnalysis: runs-on: macos-14 @@ -118,45 +100,44 @@ jobs: timeout-minutes: 30 steps: - - uses: actions/setup-python@v5 - with: - python-version: ${{ env.python_version }} - - - name: Use Xcode ${{ env.xcode_version }} - shell: bash - run: | - XCODE_DEVELOPER_DIR="/Applications/Xcode_${{ env.xcode_version }}.app/Contents/Developer" - sudo xcode-select --switch "${XCODE_DEVELOPER_DIR}" - - - uses: actions/checkout@v4 - - - name: Generate compile_commands.json and ONNX protobuf files - shell: bash - run: | - python ./tools/ci_build/build.py \ - --build_dir ./build \ - --cmake_generator "Unix Makefiles" \ - --config Debug \ - --build_shared_lib \ - --use_coreml \ - --build_objc \ - --enable_training_apis \ - --cmake_extra_defines CMAKE_EXPORT_COMPILE_COMMANDS=ON \ - --use_binskim_compliant_compile_flags \ - --update \ - --build --parallel \ - --target onnx_proto - - - name: Analyze Objective-C/C++ source code - shell: bash - run: | - CLANG_TIDY_CHECKS="-*,clang-analyzer-*" - - "$(brew --prefix llvm@15)/bin/clang-tidy" \ - -p=./build/Debug \ - --checks="${CLANG_TIDY_CHECKS}" \ - --warnings-as-errors="${CLANG_TIDY_CHECKS}" \ - --header-filter="objectivec/include|objectivec|onnxruntime/core" \ - ./objectivec/*.mm \ - ./onnxruntime/core/platform/apple/logging/apple_log_sink.mm \ - ./onnxruntime/core/providers/coreml/model/*.mm + - name: Checkout code + uses: actions/checkout@v4 + + - name: macOS CI pipeline prepare steps + uses: ./.github/actions/macos-ci-setup + with: + platform_machine: "arm64" + python_version: ${{ env.python_version }} + xcode_version: ${{ env.xcode_version }} + use_cache: false + + - name: Generate compile_commands.json and ONNX protobuf files + shell: bash + run: | + python ./tools/ci_build/build.py \ + --build_dir ./build \ + --cmake_generator "Unix Makefiles" \ + --config Debug \ + --build_shared_lib \ + --use_coreml \ + --build_objc \ + --enable_training_apis \ + --cmake_extra_defines CMAKE_EXPORT_COMPILE_COMMANDS=ON \ + --use_binskim_compliant_compile_flags \ + --update \ + --build --parallel \ + --target onnx_proto + + - name: Analyze Objective-C/C++ source code + shell: bash + run: | + CLANG_TIDY_CHECKS="-*,clang-analyzer-*" + + "$(brew --prefix llvm@15)/bin/clang-tidy" \ + -p=./build/Debug \ + --checks="${CLANG_TIDY_CHECKS}" \ + --warnings-as-errors="${CLANG_TIDY_CHECKS}" \ + --header-filter="objectivec/include|objectivec|onnxruntime/core" \ + ./objectivec/*.mm \ + ./onnxruntime/core/platform/apple/logging/apple_log_sink.mm \ + ./onnxruntime/core/providers/coreml/model/*.mm diff --git a/.github/workflows/macos-ci-build-and-test-workflow.yml b/.github/workflows/macos-ci-build-and-test-workflow.yml new file mode 100644 index 0000000000000..dfe97f8370e99 --- /dev/null +++ b/.github/workflows/macos-ci-build-and-test-workflow.yml @@ -0,0 +1,113 @@ +name: "macOS CI Reusable Workflow for build and test" +description: "This is a reusable workflow for macOS CI pipelines to build and test" + +on: + workflow_call: + inputs: + use_webgpu: + required: false + type: boolean + default: false + use_xnnpack: + required: false + type: boolean + default: false + use_coreml: + required: false + type: boolean + default: false + python_version: + required: false + type: string + default: "3.11" + matrix_exclude: + required: false + type: string + description: "JSON string specifying combinations to exclude from the matrix" + # we do not have enough resources to run all combinations + # Exclude x86_64 + Debug combination by default + default: >- + [ + {"platform_machine": "x86_64", "build_config": "Debug"} + ] + +jobs: + build-and-test: + strategy: + matrix: + platform_machine: ["x86_64", "arm64"] + build_config: ["Debug", "Release"] + exclude: ${{ fromJSON(inputs.matrix_exclude) }} + + runs-on: ${{ matrix.platform_machine == 'x86_64' && 'macos-13' || 'macos-15' }} + env: + build_flags: > + --build_dir ./build + --skip_submodule_sync + --parallel + --use_binskim_compliant_compile_flags + --build_shared_lib + --build_nodejs + --build_objc + --build_java + --build_wheel + ${{ inputs.use_webgpu && '--use_webgpu' || '' }} + ${{ inputs.use_xnnpack && '--use_xnnpack' || '' }} + ${{ inputs.use_coreml && '--use_coreml' || '' }} + --use_vcpkg --use_vcpkg_ms_internal_asset_cache + --config ${{ matrix.build_config }} + xcode_version: ${{ matrix.platform_machine == 'x86_64' && '14.3.1' || '16' }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: macOS CI pipeline prepare steps + uses: ./.github/actions/macos-ci-setup + with: + platform_machine: ${{ matrix.platform_machine }} + python_version: ${{ inputs.python_version }} + xcode_version: ${{ env.xcode_version }} + use_cache: true + + - uses: actions/cache@v4 + id: onnx-node-tests-cache + with: + path: ${{ github.workspace }}/js/test/ + key: onnxnodetests-${{ hashFiles('js/scripts/prepare-onnx-node-tests.ts') }} + + - name: Setup environment variables + shell: bash + run: | + set -e -x + export PATH=${{ github.workspace }}/build/installed/bin:$PATH + export ONNX_ML=1 + export CMAKE_ARGS="-DONNX_GEN_PB_TYPE_STUBS=ON -DONNX_WERROR=OFF" + python -m pip install -r '${{ github.workspace }}/tools/ci_build/github/linux/docker/scripts/requirements.txt' + + - name: Configure Build (build.py --update) + shell: bash + working-directory: ${{ github.workspace }} + run: | + rm -rf ${{ github.workspace }}/build/${{ matrix.build_config }} + python ./tools/ci_build/build.py --update ${{ env.build_flags }} + + - name: Build (build.py --build) + shell: bash + working-directory: ${{ github.workspace }} + run: | + python ./tools/ci_build/build.py --build ${{ env.build_flags }} + + - name: Install + shell: bash + run: | + set -e -x + rm -rf ${{ github.workspace }}/build/installed + cd ${{ github.workspace }}/build/${{ matrix.build_config }} + make install DESTDIR=${{ github.workspace }}/build/installed + + - name: Running Tests (build.py --test) + shell: bash + working-directory: ${{ github.workspace }} + run: | + python ./tools/ci_build/build.py --test ${{ env.build_flags }} diff --git a/.github/workflows/reusable_linux_build.yml b/.github/workflows/reusable_linux_build.yml new file mode 100644 index 0000000000000..7ff9260558ebf --- /dev/null +++ b/.github/workflows/reusable_linux_build.yml @@ -0,0 +1,185 @@ +name: Reusable Linux CPU/GPU Build and Test + +on: + workflow_call: + inputs: + pool_name: + description: 'The specific 1ES pool name (e.g., onnxruntime-github-Ubuntu2204-AMD-CPU)' + required: true + type: string + build_config: + description: 'Build configuration (Debug or Release)' + required: true + type: string + architecture: + description: 'Target architecture (x64 or arm64)' + required: true + type: string + dockerfile_path: + description: 'Path to the Dockerfile relative to the workspace root' + required: true + type: string + docker_image_repo: + description: 'Name for the Docker image repository' + required: true + type: string + docker_build_args: + description: 'Arguments to pass to the docker image build command' + required: false + type: string + default: '' + execution_providers: + description: 'Space-separated list of execution providers to enable (passed to build.py)' + required: false + type: string + default: '' + extra_build_flags: + description: 'Additional flags for the build.py script (appended after EP flags)' + required: false + type: string + default: '' + python_path_prefix: + description: 'Optional prefix to add to the PATH for python command (e.g., PATH=/opt/python/cp310-cp310/bin:$PATH)' + required: false + type: string + default: '' + python_version: + description: 'Python version to set up on the runner host' + required: false + type: string + default: '3.x' + run_tests: + description: 'Whether to execute the test suite after building' + required: false + type: boolean + default: true + upload_build_output: + description: 'Whether to upload the build output directory as an artifact (used when tests are skipped)' + required: false + type: boolean + default: false + secrets: + GH_TOKEN: + description: 'GitHub token for accessing actions/packages' + required: true + +jobs: + build_test_pipeline: + runs-on: + - self-hosted + - "1ES.Pool=${{ inputs.pool_name }}" + permissions: + contents: read + packages: write + attestations: write + id-token: write + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python ${{ inputs.python_version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ inputs.python_version }} + + - name: Build Docker Image (${{ inputs.architecture }} / ${{ inputs.build_config }}) + uses: microsoft/onnxruntime-github-actions/build-docker-image@v0.0.5 + id: build_docker_image_step + with: + dockerfile: ${{ github.workspace }}/${{ inputs.dockerfile_path }} + image-name: ghcr.io/microsoft/onnxruntime/${{ inputs.docker_image_repo }} + build-args: ${{ inputs.docker_build_args }} + push: true + azure-container-registry-name: onnxruntimebuildcache + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + # ------------- Update Step (CMake Generation) ------------- + - name: Generate Build Files (CMake) (${{ inputs.architecture }} / ${{ inputs.build_config }}) + id: update_step + uses: microsoft/onnxruntime-github-actions/run-build-script-in-docker@v0.0.5 + with: + docker_image: ${{ steps.build_docker_image_step.outputs.full-image-name }} + build_config: ${{ inputs.build_config }} + mode: 'update' + execution_providers: ${{ inputs.execution_providers }} # Pass down EP list + extra_build_flags: ${{ inputs.extra_build_flags }} + python_path_prefix: ${{ inputs.python_path_prefix }} + + # ------------- Build Step (Compilation) ------------- + - name: Build ONNX Runtime (${{ inputs.architecture }} / ${{ inputs.build_config }}) + id: build_step + uses: microsoft/onnxruntime-github-actions/run-build-script-in-docker@v0.0.5 + with: + docker_image: ${{ steps.build_docker_image_step.outputs.full-image-name }} + build_config: ${{ inputs.build_config }} + mode: 'build' + execution_providers: ${{ inputs.execution_providers }} # Pass down EP list + extra_build_flags: ${{ inputs.extra_build_flags }} + python_path_prefix: ${{ inputs.python_path_prefix }} + + # ------------- Test Step ------------- + - name: Test ONNX Runtime (${{ inputs.architecture }} / ${{ inputs.build_config }}) + id: test_step + if: inputs.run_tests == true + uses: microsoft/onnxruntime-github-actions/run-build-script-in-docker@v0.0.5 + with: + docker_image: ${{ steps.build_docker_image_step.outputs.full-image-name }} + build_config: ${{ inputs.build_config }} + mode: 'test' + execution_providers: ${{ inputs.execution_providers }} # Pass down EP list + extra_build_flags: ${{ inputs.extra_build_flags }} + python_path_prefix: ${{ inputs.python_path_prefix }} + + # ------------- Prepare Artifact Step ------------- + - name: Prepare Build Output for Upload + if: inputs.upload_build_output == true + shell: bash + run: | + #!/bin/bash + set -e -x + BUILD_DIR="${{ runner.temp }}/${{ inputs.build_config }}" + if [ ! -d "${BUILD_DIR}" ]; then + echo "Error: Build directory ${BUILD_DIR} not found. Cannot prepare artifact." + exit 1 + fi + echo "--- Cleaning build directory: ${BUILD_DIR} ---" + rm -rf "${BUILD_DIR}/onnxruntime" || true + rm -rf "${BUILD_DIR}/pybind11" || true + rm -rf "${BUILD_DIR}/vcpkg_installed" || true + rm -f "${BUILD_DIR}/models" || true + DEPS_DIR="${BUILD_DIR}/_deps" + if [ -d "${DEPS_DIR}" ]; then + echo "Cleaning ${DEPS_DIR}, keeping onnx-src..." + find "${DEPS_DIR}" -mindepth 1 ! -regex "^${DEPS_DIR}/onnx-src\(/.*\)?$" -delete + else + echo "${DEPS_DIR} does not exist, skipping deps cleanup." + fi + echo "--- Saving executable permissions ---" + cd "${BUILD_DIR}" + find . -executable -type f -printf '%p\n' > perms.txt + echo "--- Cleanup and permission saving complete for ${BUILD_DIR} ---" + + # ------------- Upload Build Output Step ------------- + - name: Upload Build Output Artifact + if: inputs.upload_build_output == true + uses: actions/upload-artifact@v4 + with: + name: build-output-${{ inputs.architecture }}-${{ inputs.build_config }} + path: ${{ runner.temp }}/${{ inputs.build_config }} + if-no-files-found: error + + # ------------- Upload Log on Build Failure Step ------------- + - name: Upload VCPKG Manifest Install Log on Update or Build Failure + if: steps.update_step.outcome == 'failure' || steps.build_step.outcome == 'failure' + uses: actions/upload-artifact@v4 + with: + name: vcpkg-manifest-install-log-${{ inputs.architecture }}-${{ inputs.build_config }} + path: ${{ runner.temp }}/${{ inputs.build_config }}/${{ inputs.build_config }}/vcpkg-manifest-install.log + if-no-files-found: ignore diff --git a/.github/workflows/web.yml b/.github/workflows/web.yml new file mode 100644 index 0000000000000..8490252ca657b --- /dev/null +++ b/.github/workflows/web.yml @@ -0,0 +1,71 @@ +name: Web CI Pipeline + +on: + push: + branches: + - main + - rel-* + pull_request: + branches: + - main + - rel-* + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + precheck: + runs-on: ubuntu-latest + outputs: + commit_sha: ${{ steps.extract_commit.outputs.commit_sha }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + submodules: true + + - name: Init and Precheck + uses: ./.github/actions/linux-web-init-and-check + + - name: Extract commit SHA + id: extract_commit + run: echo "commit_sha=${{ github.sha }}" >> $GITHUB_OUTPUT + shell: bash + + wasm_Debug: + needs: precheck + uses: ./.github/workflows/linux-wasm-ci-build-and-test-workflow.yml + with: + build_config: Debug + extra_build_args: "--enable_wasm_profiling" + build_jsep: true + build_webgpu: true + + wasm_Release: + needs: precheck + uses: ./.github/workflows/linux-wasm-ci-build-and-test-workflow.yml + with: + build_config: Release + extra_build_args: "--target onnxruntime_webassembly --skip_tests --enable_wasm_api_exception_catching --disable_rtti" + build_jsep: true + build_webgpu: true + + web_Debug: + needs: + - precheck + - wasm_Debug + uses: ./.github/workflows/windows-web-ci-workflow.yml + with: + commit_override: ${{ needs.precheck.outputs.commit_sha }} + build_config: Debug + + web_Release: + needs: + - precheck + - wasm_Release + uses: ./.github/workflows/windows-web-ci-workflow.yml + with: + commit_override: ${{ needs.precheck.outputs.commit_sha }} + build_config: Release diff --git a/.github/workflows/windows-web-ci-workflow.yml b/.github/workflows/windows-web-ci-workflow.yml new file mode 100644 index 0000000000000..57f687d8502ff --- /dev/null +++ b/.github/workflows/windows-web-ci-workflow.yml @@ -0,0 +1,248 @@ +name: "Windows Web CI Workflow" +description: "Windows Web CI pipeline for building and testing ONNX Runtime Web" + +on: + workflow_call: + inputs: + commit_override: + type: string + default: "" + build_config: + type: string + default: "Debug" + npm_packaging_mode: + type: string + default: "dev" + package_name: + type: string + default: "NPM_packages" + run_webgpu_tests: + type: boolean + default: true + +jobs: + build_onnxruntime_web: + runs-on: ["self-hosted", "1ES.Pool=onnxruntime-github-Win2022-WEBGPU-A10"] + + env: + webgpu_commandline_extra_flags: "--chromium-flags=--ignore-gpu-blocklist --chromium-flags=--gpu-vendor-id=0x10de" + CHROME_BIN: 'C:\Program Files\Google\Chrome\Application\chrome.exe' + + timeout-minutes: 60 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: false + + - name: Read commit SHA and checkout + if: ${{ inputs.commit_override != '' }} + shell: cmd + run: | + git fetch origin +${{ inputs.commit_override }}:refs/remotes/origin/${{ inputs.commit_override }} + git checkout --force ${{ inputs.commit_override }} + + - name: Write commit SHA to __commit.txt + if: ${{ inputs.commit_override == '' }} + shell: cmd + run: | + echo.${{ github.sha }}>${{ github.workspace }}/__commit.txt + + - name: Checkout submodule onnx + shell: cmd + run: | + git submodule sync -- cmake\external\onnx + git submodule update --init -- cmake\external\onnx + + - name: Force EOL to LF on windows for /js/** + shell: cmd + run: | + echo.>>.gitattributes + echo /js/** text=auto eol=lf>>.gitattributes + rd /s /q js + git checkout -- js/** + git checkout -- .gitattributes + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20.x" + + - name: Download WebAssembly artifacts + uses: actions/download-artifact@v4 + with: + name: ${{ inputs.build_config }}_wasm + path: ${{ github.workspace }}/artifacts_wasm + + - name: Binplace dist files (.wasm) + shell: cmd + run: | + mkdir ${{ github.workspace }}\js\web\dist + copy ${{ github.workspace }}\artifacts_wasm\ort-*.wasm ${{ github.workspace }}\js\web\dist\ + + - name: Binplace dist files (.mjs) + shell: cmd + run: | + copy ${{ github.workspace }}\artifacts_wasm\ort-*.mjs ${{ github.workspace }}\js\web\dist\ + + - name: npm ci for /js/ + run: npm ci + working-directory: ${{ github.workspace }}/js + + - name: npm ci for /js/common/ + run: npm ci + working-directory: ${{ github.workspace }}/js/common + + - name: npm ci for /js/web/ + run: npm ci + working-directory: ${{ github.workspace }}/js/web + + - uses: actions/cache@v4 + id: onnx-node-tests-cache + with: + path: ${{ github.workspace }}/js/test/ + key: onnxnodetests-${{ hashFiles('js/scripts/prepare-onnx-node-tests.ts') }} + + - name: Pack NPM packages + shell: pwsh + run: | + . ${{ github.workspace }}\tools\ci_build\github\js\pack-npm-packages.ps1 ${{ inputs.npm_packaging_mode }} ${{ github.workspace }} web + + - name: Check active Chrome processes (before test) + if: ${{ runner.debug == '1' }} + shell: pwsh + run: | + Get-WmiObject Win32_Process -Filter "name = 'chrome.exe'" | Format-List CommandLine + + - name: Run ort-web tests (wasm,webgl backend) + if: ${{ inputs.run_webgpu_tests != true }} + shell: cmd + run: | + mkdir ${{ runner.temp }}\web\test\01 + dir ${{ runner.temp }}\web\test\01 + npm test -- -e=chrome -b=webgl,wasm --user-data-dir=${{ runner.temp }}\web\test\01 --chromium-flags=--enable-logging --chromium-flags=--v=1 + working-directory: ${{ github.workspace }}\js\web + + - name: Run ort-web tests (ALL backends) + if: ${{ inputs.run_webgpu_tests == true }} + shell: cmd + run: | + mkdir ${{ runner.temp }}\web\test\02 + dir ${{ runner.temp }}\web\test\02 + npm test -- -e=chrome -b=webgl,wasm,webgpu ${{ env.webgpu_commandline_extra_flags }} --user-data-dir=${{ runner.temp }}\web\test\02 --chromium-flags=--enable-logging --chromium-flags=--v=1 + working-directory: ${{ github.workspace }}\js\web + + - name: Run ort-web tests (Suite1, webgpu, IO-binding=gpu-tensor) + if: ${{ inputs.run_webgpu_tests == true }} + shell: cmd + run: | + mkdir ${{ runner.temp }}\web\test\03 + dir ${{ runner.temp }}\web\test\03 + npm test -- suite1 -e=chrome -b=webgpu --io-binding=gpu-tensor ${{ env.webgpu_commandline_extra_flags }} --user-data-dir=${{ runner.temp }}\web\test\03 --chromium-flags=--enable-logging --chromium-flags=--v=1 + working-directory: ${{ github.workspace }}\js\web + + - name: Run ort-web tests (Suite1, webgpu, IO-binding=gpu-location) + if: ${{ inputs.run_webgpu_tests == true }} + shell: cmd + run: | + mkdir ${{ runner.temp }}\web\test\04 + dir ${{ runner.temp }}\web\test\04 + npm test -- suite1 -e=chrome -b=webgpu --io-binding=gpu-location ${{ env.webgpu_commandline_extra_flags }} --user-data-dir=${{ runner.temp }}\web\test\04 --chromium-flags=--enable-logging --chromium-flags=--v=1 + working-directory: ${{ github.workspace }}\js\web + + - name: Run ort-web tests - WebGL packed mode + shell: cmd + run: | + mkdir ${{ runner.temp }}\web\test\05 + dir ${{ runner.temp }}\web\test\05 + npm test -- --webgl.pack -b=webgl -e=chrome --user-data-dir=${{ runner.temp }}\web\test\05 --chromium-flags=--enable-logging --chromium-flags=--v=1 + working-directory: ${{ github.workspace }}\js\web + + - name: Run ort-web tests - WebAssembly proxy + if: ${{ inputs.build_config == 'Release' }} + shell: cmd + run: | + mkdir ${{ runner.temp }}\web\test\06 + dir ${{ runner.temp }}\web\test\06 + npm test -- --wasm.proxy -b=wasm -e=chrome --user-data-dir=${{ runner.temp }}\web\test\06 --chromium-flags=--enable-logging --chromium-flags=--v=1 + working-directory: ${{ github.workspace }}\js\web + + # WebGPU EP tests + - name: Download WebAssembly WebGPU artifacts + if: ${{ inputs.run_webgpu_tests == true }} + uses: actions/download-artifact@v4 + with: + name: ${{ inputs.build_config }}_wasm_webgpu + path: ${{ github.workspace }}/artifacts_wasm_webgpu + + - name: Binplace dist files (.wasm) for WebGPU + if: ${{ inputs.run_webgpu_tests == true }} + shell: cmd + run: | + copy /Y ${{ github.workspace }}\artifacts_wasm_webgpu\ort-*.wasm ${{ github.workspace }}\js\web\dist\ + + - name: Binplace dist files (.mjs) for WebGPU + if: ${{ inputs.run_webgpu_tests == true }} + shell: cmd + run: | + copy /Y ${{ github.workspace }}\artifacts_wasm_webgpu\ort-*.mjs ${{ github.workspace }}\js\web\dist\ + + - name: Run ort-web tests - WebGPU EP + if: ${{ inputs.run_webgpu_tests == true }} + continue-on-error: true + shell: cmd + run: | + mkdir ${{ runner.temp }}\web\test\07 + dir ${{ runner.temp }}\web\test\07 + npm test --webgpu-ep -- suite1 ${{ inputs.build_config == 'Debug' && '--log-verbose' || '' }} -b=webgpu -e=chrome ${{ env.webgpu_commandline_extra_flags }} --user-data-dir=${{ runner.temp }}\web\test\07 --chromium-flags=--enable-logging --chromium-flags=--v=1 + working-directory: ${{ github.workspace }}\js\web + + - name: Validate shader keys - WebGPU EP + if: ${{ inputs.run_webgpu_tests == true && inputs.build_config == 'Debug' }} + uses: ./.github/actions/webgpu-validate-shader-key + with: + log_file_path: ${{ runner.temp }}\web\test\07\chrome_debug.log + is_chromium_log: true + + - name: E2E package consuming test + if: ${{ inputs.build_config == 'Release' }} + run: npm run test:e2e -- --browser=Chrome_default + working-directory: ${{ github.workspace }}\js\web + + - name: Create artifacts directory + if: ${{ inputs.build_config == 'Release' }} + shell: cmd + run: mkdir ${{ github.workspace }}\artifacts_npm + + - name: Copy onnxruntime-common artifacts + if: ${{ inputs.build_config == 'Release' }} + shell: cmd + run: | + if exist ${{ github.workspace }}\js\common\onnxruntime-common-*.tgz ( + copy ${{ github.workspace }}\js\common\onnxruntime-common-*.tgz ${{ github.workspace }}\artifacts_npm\ + ) + + - name: Copy onnxruntime-web artifacts + if: ${{ inputs.build_config == 'Release' }} + shell: cmd + run: copy ${{ github.workspace }}\js\web\onnxruntime-web-*.tgz ${{ github.workspace }}\artifacts_npm\ + + - name: Upload NPM packages + if: ${{ inputs.build_config == 'Release' }} + uses: actions/upload-artifact@v4 + with: + name: ${{ inputs.package_name }} + path: ${{ github.workspace }}\artifacts_npm + + - name: Log Chrome processes (after test) + if: ${{ always() && runner.debug == '1' }} + shell: cmd + run: | + for %%i in (01 02 03 04 05 06 07) do ( + if exist ${{ runner.temp }}\web\test\%%i ( + echo ------------------- BEGIN %%i ------------------- + type ${{ runner.temp }}\web\test\%%i\chrome_debug.log + echo ------------------- END %%i ------------------- + ) + ) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml deleted file mode 100644 index 593ca85e8ea4b..0000000000000 --- a/.github/workflows/windows.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Windows_CI -on: - push: - branches: - - main - - rel-* - pull_request: - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -env: - AZCOPY_AUTO_LOGIN_TYPE: MSI - AZCOPY_MSI_CLIENT_ID: 63b63039-6328-442f-954b-5a64d124e5b4 - -jobs: - Windows-CUDA-12: - runs-on: ["self-hosted", "1ES.Pool=onnxruntime-github-vs2022-mms"] - steps: - - uses: actions/checkout@v4 - with: - submodules: false - - uses: actions/setup-python@v5 - with: - python-version: '3.11.x' - architecture: 'x64' - - - uses: actions/setup-node@v4 - with: - node-version: 18 - - - name: Download cuda - run: azcopy.exe cp --recursive "https://lotusscus.blob.core.windows.net/models/cuda_sdk/v12.2" cuda_sdk - - - - name: Delete build folder - run: | - if (Test-Path D:\b) { Remove-Item -Recurse -Force D:\b } - - - # The build machine doesn't have a GPU. So the value of CMAKE_CUDA_ARCHITECTURES doesn't matter. - - name: Build code - run: python tools\ci_build\build.py --windows_sdk_version 10.0.22621.0 --enable_training --build_java --config Debug --build_dir D:\b --skip_submodule_sync --build_csharp --update --build --parallel --cmake_generator "Visual Studio 17 2022" --build_shared_lib --enable_pybind --use_cuda --cuda_home=${{ github.workspace }}\cuda_sdk\v12.2 --enable_cuda_profiling --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=75 \ No newline at end of file diff --git a/.github/workflows/windows_build_x64_asan.yml b/.github/workflows/windows_build_x64_asan.yml new file mode 100644 index 0000000000000..b42fbac33d549 --- /dev/null +++ b/.github/workflows/windows_build_x64_asan.yml @@ -0,0 +1,49 @@ +# .github/workflows/build_x64_asan.yml +name: windows_x64_asan + +on: + push: + branches: [ main, 'rel-*'] + pull_request: + branches: [ main ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build_x64: + runs-on: ["self-hosted", "1ES.Pool=onnxruntime-github-vs2022-mms"] + timeout-minutes: 300 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: false + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + architecture: x64 + + - name: Locate vcvarsall and Setup Env + uses: ./.github/actions/locate-vcvarsall-and-setup-env # Use the composite action + with: + architecture: x64 + + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Build and Test (Combined) + shell: cmd + run: | + @echo off + echo %PATH% + python -m pip install -r "%GITHUB_WORKSPACE%\tools\ci_build/github/windows\python\requirements.txt" + python "%GITHUB_WORKSPACE%\tools\ci_build\build.py" --config Debug --build_dir "%RUNNER_TEMP%\build" --skip_submodule_sync --parallel --use_vcpkg --use_vcpkg_ms_internal_asset_cache --cmake_generator "Visual Studio 17 2022" --disable_memleak_checker --enable_address_sanitizer diff --git a/.github/workflows/windows_cuda.yml b/.github/workflows/windows_cuda.yml new file mode 100644 index 0000000000000..0687bf0a2529d --- /dev/null +++ b/.github/workflows/windows_cuda.yml @@ -0,0 +1,141 @@ +name: ONNX Runtime CUDA Builds + +on: + push: + branches: + - main + - rel-* + pull_request: + branches: + - main + - rel-* + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build_x64_RelWithDebInfo: + name: Windows GPU CUDA CI Pipeline # Job name set here + runs-on: ["self-hosted", "1ES.Pool=onnxruntime-github-Win2022-GPU-A10"] + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Fetch all history for all tags and branches + submodules: 'none' + + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + architecture: x64 + + - name: Locate vcvarsall and Setup Env + uses: ./.github/actions/locate-vcvarsall-and-setup-env + with: + architecture: x64 + + - name: Install python modules + run: python -m pip install -r .\tools\ci_build\github\windows\python\requirements.txt + working-directory: ${{ github.workspace }} + shell: cmd + + - name: Download CUDA SDK v12.2 + working-directory: ${{ runner.temp }} + run: | + azcopy.exe cp --recursive "https://lotusscus.blob.core.windows.net/models/cuda_sdk/v12.2" . + dir + shell: pwsh + + - name: Add CUDA to PATH + shell: powershell + run: | + Write-Host "Adding CUDA to PATH" + Write-Host "CUDA Path: $env:RUNNER_TEMP\v12.2\bin" + Add-Content -Path $env:GITHUB_PATH -Value "$env:RUNNER_TEMP\v12.2\bin" + Add-Content -Path $env:GITHUB_PATH -Value "$env:RUNNER_TEMP\v12.2\extras\CUPTI\lib64" + + - uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + architecture: x64 + + - uses: actions/cache@v4 + id: onnx-node-tests-cache + with: + path: ${{ github.workspace }}/js/test/ + key: onnxnodetests-${{ hashFiles('js/scripts/prepare-onnx-node-tests.ts') }} + + - name: API Documentation Check and generate + run: | + set ORT_DOXY_SRC=${{ github.workspace }} + set ORT_DOXY_OUT=${{ runner.temp }}\build\RelWithDebInfo\RelWithDebInfo + mkdir %ORT_DOXY_SRC% + mkdir %ORT_DOXY_OUT% + "C:\Program Files\doxygen\bin\doxygen.exe" ${{ github.workspace }}\tools\ci_build\github\Doxyfile_csharp.cfg + working-directory: ${{ github.workspace }} + shell: cmd + + - uses: actions/setup-dotnet@v4 + env: + PROCESSOR_ARCHITECTURE: x64 + with: + dotnet-version: '8.x' + + - name: Use Nuget 6.x + uses: nuget/setup-nuget@v2 + with: + nuget-version: '6.x' + + - name: NuGet restore + run: nuget restore ${{ github.workspace }}\packages.config -ConfigFile ${{ github.workspace }}\NuGet.config -PackagesDirectory ${{ runner.temp }}\build\RelWithDebInfo + shell: cmd + + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Set OnnxRuntimeBuildDirectory + shell: pwsh + run: | + $buildDir = Join-Path ${{ runner.temp }} "build" + echo "OnnxRuntimeBuildDirectory=$buildDir" >> $env:GITHUB_ENV + + - name: Build and Test + working-directory: ${{ runner.temp }} + run: | + python.exe ${{ github.workspace }}\tools\ci_build\build.py --config RelWithDebInfo --build_dir build --skip_submodule_sync --build_csharp --parallel --use_binskim_compliant_compile_flags --cmake_generator "Visual Studio 17 2022" --build_shared_lib --enable_onnx_tests --build_wheel --build_java --build_nodejs --use_cuda --cuda_home="$env:RUNNER_TEMP\v12.2" --enable_cuda_profiling --enable_transformers_tool_test --use_vcpkg --use_vcpkg_ms_internal_asset_cache --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=86 --cmake_extra_defines onnxruntime_BUILD_UNIT_TESTS=ON --cmake_extra_defines onnxruntime_ENABLE_CUDA_EP_INTERNAL_TESTS=ON + if ($lastExitCode -ne 0) { + exit $lastExitCode + } + Remove-Item "${{ runner.temp }}\build\RelWithDebInfo" -Include "*.obj" -Recurse + shell: pwsh + + - name: Validate C# native delegates + run: python tools\ValidateNativeDelegateAttributes.py + working-directory: ${{ github.workspace }}\csharp + shell: cmd + + - name: Install ONNX Runtime Wheel + uses: ./.github/actions/install-onnxruntime-wheel + with: + whl-directory: ${{ runner.temp }}\build\RelWithDebInfo\RelWithDebInfo\dist + + timeout-minutes: 300 + env: + OrtPackageId: Microsoft.ML.OnnxRuntime.Gpu + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + setVcvars: true + ALLOW_RELEASED_ONNX_OPSET_ONLY: '0' + DocUpdateNeeded: false + ONNXRUNTIME_TEST_GPU_DEVICE_ID: '0' + AZCOPY_AUTO_LOGIN_TYPE: MSI + AZCOPY_MSI_CLIENT_ID: 63b63039-6328-442f-954b-5a64d124e5b4 diff --git a/.github/workflows/windows_dml.yml b/.github/workflows/windows_dml.yml new file mode 100644 index 0000000000000..57656d951d40a --- /dev/null +++ b/.github/workflows/windows_dml.yml @@ -0,0 +1,116 @@ +name: ONNX Runtime DirectML Builds + +on: + push: + branches: + - main + - rel-* + pull_request: + branches: + - main + - rel-* + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build_x64_RelWithDebInfo: + name: Windows GPU DML CI Pipeline + env: + OrtPackageId: Microsoft.ML.OnnxRuntime.DirectML + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + setVcvars: true + ALLOW_RELEASED_ONNX_OPSET_ONLY: '0' + DocUpdateNeeded: false + ONNXRUNTIME_TEST_GPU_DEVICE_ID: '0' + runs-on: ["self-hosted", "1ES.Pool=onnxruntime-github-Win2022-GPU-A10"] + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Fetch all history for all tags and branches + submodules: 'none' + + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + architecture: x64 + + - name: Locate vcvarsall and Setup Env + uses: ./.github/actions/locate-vcvarsall-and-setup-env + with: + architecture: x64 + + - name: Install python modules + run: python -m pip install -r .\tools\ci_build\github\windows\python\requirements.txt + working-directory: ${{ github.workspace }} + shell: cmd + + - uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + architecture: x64 + + - name: API Documentation Check and generate + run: | + set ORT_DOXY_SRC=${{ github.workspace }} + set ORT_DOXY_OUT=${{ github.workspace }}\RelWithDebInfo\RelWithDebInfo + mkdir %ORT_DOXY_SRC% + mkdir %ORT_DOXY_OUT% + "C:\Program Files\doxygen\bin\doxygen.exe" ${{ github.workspace }}\tools\ci_build\github\Doxyfile_csharp.cfg + working-directory: ${{ github.workspace }} + shell: cmd + + - uses: actions/setup-dotnet@v4 + env: + PROCESSOR_ARCHITECTURE: x64 + with: + dotnet-version: '8.x' + + - name: Use Nuget 6.x + uses: nuget/setup-nuget@v2 + with: + nuget-version: '6.x' + + - name: NuGet restore + run: nuget restore ${{ github.workspace }}\packages.config -ConfigFile ${{ github.workspace }}\NuGet.config -PackagesDirectory ${{ github.workspace }}\RelWithDebInfo + shell: cmd + + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Set OnnxRuntimeBuildDirectory + shell: pwsh + run: | + $buildDir = Join-Path ${{ runner.temp }} "build" + echo "OnnxRuntimeBuildDirectory=$buildDir" >> $env:GITHUB_ENV + + - name: Build and Test + working-directory: ${{ runner.temp }} + run: | + python.exe ${{ github.workspace }}\tools\ci_build\build.py --config RelWithDebInfo --build_dir build --skip_submodule_sync --build_csharp --parallel --use_binskim_compliant_compile_flags --cmake_generator "Visual Studio 17 2022" --build_shared_lib --enable_onnx_tests --build_wheel --use_dml --enable_wcos --use_vcpkg --use_vcpkg_ms_internal_asset_cache + if ($lastExitCode -ne 0) { + exit $lastExitCode + } + Remove-Item "${{ github.workspace }}\RelWithDebInfo" -Include "*.obj" -Recurse + shell: pwsh + + - name: Validate C# native delegates + run: python tools\ValidateNativeDelegateAttributes.py + working-directory: ${{ github.workspace }}\csharp + shell: cmd + + - name: Install ONNX Runtime Wheel + uses: ./.github/actions/install-onnxruntime-wheel + with: + whl-directory: ${{ runner.temp }}\build\RelWithDebInfo\RelWithDebInfo\dist diff --git a/.github/workflows/windows_openvino.yml b/.github/workflows/windows_openvino.yml new file mode 100644 index 0000000000000..04d252ebcba19 --- /dev/null +++ b/.github/workflows/windows_openvino.yml @@ -0,0 +1,172 @@ +name: Windows OpenVINO CI Pipeline + +on: + push: + branches: + - main + - rel-* + pull_request: + branches: + - main + - rel-* + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + BUILD_OPENVINO_EP: + name: Windows OpenVINO CI Pipeline + runs-on: ["self-hosted", "1ES.Pool=onnxruntime-github-vs2022-mms"] + timeout-minutes: 240 + env: + AZCOPY_AUTO_LOGIN_TYPE: MSI + AZCOPY_MSI_CLIENT_ID: 63b63039-6328-442f-954b-5a64d124e5b4 + OnnxRuntimeBuildDirectory: ${{ github.workspace }} + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + ALLOW_RELEASED_ONNX_OPSET_ONLY: '1' + BuildConfig: RelWithDebInfo + buildArch: x64 + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: none + + - name: Setup Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: '3.12' + architecture: x64 #Keep x64, because the original pipeline is for x64 + + - name: Locate vcvarsall and Setup Env + uses: ./.github/actions/locate-vcvarsall-and-setup-env + with: + architecture: x64 + + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Download OpenVINO Toolkit v2025.0.0 + env: + OpenVINOVersion: 2025.0.0 + shell: pwsh + run: | + $Url = "https://storage.openvinotoolkit.org/repositories/openvino/packages/2025.0/windows/openvino_toolkit_windows_2025.0.0.17942.1f68be9f594_x86_64.zip" + $OutputPath = "$env:RUNNER_TEMP\openvino.zip" + $ExtractPath = "$env:RUNNER_TEMP\openvino-v$env:OpenVINOVersion" + $TempExtractPath = "$env:RUNNER_TEMP\openvino_temp" + + # Ensure directories exist + if (Test-Path $ExtractPath) { + Remove-Item -Recurse -Force $ExtractPath + } + New-Item -ItemType Directory -Path $ExtractPath | Out-Null + New-Item -ItemType Directory -Path $TempExtractPath | Out-Null + + # Download OpenVINO ZIP + Write-Output "Downloading OpenVINO" + Invoke-WebRequest -Uri $Url -OutFile $OutputPath + + # Extract to temporary directory first + Write-Output "Extracting OpenVINO to a temporary directory" + Expand-Archive -Path $OutputPath -DestinationPath $TempExtractPath -Force + + # Locate the nested subdirectory + $InnerFolder = Get-ChildItem -Path $TempExtractPath -Directory | Select-Object -First 1 + + if ($InnerFolder) { + Write-Output "Moving extracted files to final destination" + Move-Item -Path "$($InnerFolder.FullName)\*" -Destination $ExtractPath -Force + } else { + Write-Error "Extraction failed: No expected subdirectory found in $TempExtractPath." + Write-Error "The archive may not have extracted correctly, or its structure is different than expected." + exit 1 + } + + # Clean up temporary files + Remove-Item -Recurse -Force $TempExtractPath + Remove-Item -Force $OutputPath + + # Confirm success + Write-Output "OpenVINO extracted to $ExtractPath" + + - name: Set OpenVINORootDir + shell: pwsh + # Use $GITHUB_ENV to set the variable for subsequent steps + run: | + $openVinoRootDir = Join-Path $env:RUNNER_TEMP "openvino-v2025.0.0" + echo "OpenVINORootDir=$openVinoRootDir" >> $env:GITHUB_ENV + + - name: Print OpenVINORootDir after downloading OpenVINO + shell: cmd + run: 'echo %OpenVINORootDir%' + + - name: Print contents of OpenVINO Toolkit + shell: cmd + run: 'dir %OpenVINORootDir%' + + - name: Set up OpenVINO environment + shell: pwsh + run: | + Write-Output "Setting up OpenVINO environment variables" + . "$env:OpenVINORootDir\setupvars.ps1" + + Write-Output "Exporting selected environment variables to pipeline" + + $vars = @( + "INTEL_OPENVINO_DIR", + "OpenVINO_DIR", + "OpenVINOGenAI_DIR", + "OPENVINO_LIB_PATHS", + "TBB_DIR", + "PATH", + "PYTHONPATH" + ) + + foreach ($var in $vars) { + if (Test-Path "Env:$var") { + $value = [System.Environment]::GetEnvironmentVariable($var, "Process") + Write-Output "Setting $var=$value" + echo "$var=$value" >> $env:GITHUB_ENV # Append to GITHUB_ENV + } else { + Write-Output "Warning: $var is not set." + } + } + + Write-Output "Selected environment variables exported successfully" + + + + - name: Generate onnxruntime.sln + shell: pwsh + working-directory: ${{ runner.temp }} + run: | + python.exe ${{ github.workspace }}\tools\ci_build\build.py --config ${{ env.BuildConfig }} --build_dir build --cmake_generator "Visual Studio 17 2022" --build_shared_lib --use_openvino CPU --use_binskim_compliant_compile_flags --update --parallel + + - name: Build + shell: pwsh + working-directory: ${{ runner.temp }} + run: | + python.exe ${{ github.workspace }}\tools\ci_build\build.py --config ${{ env.BuildConfig }} --build_dir build --cmake_generator "Visual Studio 17 2022" --build_shared_lib --use_openvino CPU --use_binskim_compliant_compile_flags --build --parallel + + + - name: Run unit tests + shell: pwsh + working-directory: ${{ runner.temp }} + run: | + python "${{ github.workspace }}\tools\ci_build\build.py" ` + --config "${{ env.BuildConfig }}" ` + --build_dir build ` + --cmake_generator "Visual Studio 17 2022" ` + --build_shared_lib ` + --use_openvino CPU ` + --use_binskim_compliant_compile_flags ` + --test --enable_onnx_tests diff --git a/.github/workflows/windows_tensorrt.yml b/.github/workflows/windows_tensorrt.yml new file mode 100644 index 0000000000000..cf1658b390fad --- /dev/null +++ b/.github/workflows/windows_tensorrt.yml @@ -0,0 +1,101 @@ +name: Windows GPU TensorRT CI Pipeline + +on: + push: + branches: + - main + - rel-* + pull_request: + branches: + - main + - rel-* + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + Windows_GPU_TensorRT_CI_Pipeline: + name: Windows GPU TensorRT CI Pipeline + runs-on: ["self-hosted", "1ES.Pool=onnxruntime-github-Win2022-GPU-A10"] + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Fetch all history for all tags and branches + submodules: 'none' + + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + architecture: x64 + + - name: Locate vcvarsall and Setup Env + uses: ./.github/actions/locate-vcvarsall-and-setup-env + with: + architecture: x64 + + - name: Install python modules + run: python -m pip install -r ${{ github.workspace }}\tools\ci_build\github\windows\python\requirements.txt + shell: cmd + + - name: Download Primary CUDA SDK v12.2 + run: 'azcopy.exe cp --recursive "https://lotusscus.blob.core.windows.net/models/cuda_sdk/v12.2" ${{ runner.temp }}' + shell: pwsh + env: + AZCOPY_AUTO_LOGIN_TYPE: MSI + AZCOPY_MSI_CLIENT_ID: 63b63039-6328-442f-954b-5a64d124e5b4 + + - name: Download TensorRT-10.8.0.43.Windows10.x86_64.cuda-12.8 + run: 'azcopy.exe cp --recursive "https://lotusscus.blob.core.windows.net/models/local/TensorRT-10.8.0.43.Windows10.x86_64.cuda-12.8" ${{ runner.temp }}' + shell: pwsh + env: + AZCOPY_AUTO_LOGIN_TYPE: MSI + AZCOPY_MSI_CLIENT_ID: 63b63039-6328-442f-954b-5a64d124e5b4 + + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Add CUDA to PATH + shell: powershell + run: | + Write-Host "Adding CUDA to PATH" + Write-Host "CUDA Path: $env:RUNNER_TEMP\v12.2\bin" + Add-Content -Path $env:GITHUB_PATH -Value "$env:RUNNER_TEMP\v12.2\bin" + Add-Content -Path $env:GITHUB_PATH -Value "$env:RUNNER_TEMP\v12.2\extras\CUPTI\lib64" + Add-Content -Path $env:GITHUB_PATH -Value "$env:RUNNER_TEMP\TensorRT-10.8.0.43.Windows10.x86_64.cuda-12.8\lib" + + - name: Generate sln + working-directory: ${{ runner.temp }} + run: | + python ${{ github.workspace }}\tools\ci_build\build.py --config RelWithDebInfo --parallel --use_binskim_compliant_compile_flags --build_dir build --skip_submodule_sync --build_shared_lib --update --cmake_generator "Visual Studio 17 2022" --build_wheel --enable_onnx_tests --use_tensorrt --tensorrt_home="${{ runner.temp }}\TensorRT-10.8.0.43.Windows10.x86_64.cuda-12.8" --cuda_home="${{ runner.temp }}\v12.2" --use_vcpkg --use_vcpkg_ms_internal_asset_cache --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=86 + shell: cmd + + - name: Build + working-directory: ${{ runner.temp }} + run: | + python ${{ github.workspace }}\tools\ci_build\build.py --config RelWithDebInfo --parallel --use_binskim_compliant_compile_flags --build_dir build --skip_submodule_sync --build_shared_lib --build --cmake_generator "Visual Studio 17 2022" --build_wheel --enable_onnx_tests --use_tensorrt --tensorrt_home="${{ runner.temp }}\TensorRT-10.8.0.43.Windows10.x86_64.cuda-12.8" --cuda_home="${{ runner.temp }}\v12.2" --use_vcpkg --use_vcpkg_ms_internal_asset_cache --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=86 + shell: cmd + + - name: Add build dir to PATH + shell: powershell + run: | + Write-Host "Adding CUDA to PATH" + Add-Content -Path $env:GITHUB_PATH -Value "$env:RUNNER_TEMP\build\RelWithDebInfo\RelWithDebInfo" + + - name: Install ONNX Runtime Wheel + uses: ./.github/actions/install-onnxruntime-wheel + with: + whl-directory: ${{ runner.temp }}\build\RelWithDebInfo\RelWithDebInfo\dist + + - name: Run tests + working-directory: ${{ runner.temp }} + run: | + mklink /D /J ${{ github.workspace }}\RelWithDebInfo\models ${{ github.workspace }}\models + python ${{ github.workspace }}\tools\ci_build\build.py --config RelWithDebInfo --parallel --use_binskim_compliant_compile_flags --build_dir build --skip_submodule_sync --build_shared_lib --test --cmake_generator "Visual Studio 17 2022" --build_wheel --enable_onnx_tests --use_tensorrt --tensorrt_home="${{ runner.temp }}\TensorRT-10.8.0.43.Windows10.x86_64.cuda-12.8" --cuda_home="${{ runner.temp }}\v12.2" --use_vcpkg --use_vcpkg_ms_internal_asset_cache --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=86 + shell: cmd + timeout-minutes: 180 diff --git a/.github/workflows/windows_webgpu.yml b/.github/workflows/windows_webgpu.yml new file mode 100644 index 0000000000000..8b3b8a2fcde54 --- /dev/null +++ b/.github/workflows/windows_webgpu.yml @@ -0,0 +1,284 @@ +name: ONNX Runtime WebGPU Builds + +on: + push: + branches: + - main + - rel-* + pull_request: + branches: + - main + - rel-* + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + webgpu_build_x64_RelWithDebInfo: + runs-on: ["self-hosted", "1ES.Pool=onnxruntime-github-Win2022-GPU-A10"] + timeout-minutes: 300 + env: + OrtPackageId: Microsoft.ML.OnnxRuntime + OnnxRuntimeBuildDirectory: ${{ github.workspace }} + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + setVcvars: true + ALLOW_RELEASED_ONNX_OPSET_ONLY: "0" + DocUpdateNeeded: false + NVIDIA_TF32_OVERRIDE: "0" + ONNXRUNTIME_TEST_GPU_DEVICE_ID: "0" + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: none + + - name: Setup Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + architecture: x64 + + - name: Locate vcvarsall and Setup Env + uses: ./.github/actions/locate-vcvarsall-and-setup-env + with: + architecture: x64 + + - name: Install python modules + run: python -m pip install -r tools\ci_build\github\windows\python\requirements.txt + shell: cmd + working-directory: ${{ github.workspace }} + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20.x" + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: "17" + architecture: x64 + + - name: API Documentation Check and generate + run: | + set ORT_DOXY_SRC=${{ github.workspace }} + set ORT_DOXY_OUT=${{ github.workspace }}\RelWithDebInfo\RelWithDebInfo + mkdir %ORT_DOXY_SRC% + mkdir %ORT_DOXY_OUT% + "C:\Program Files\doxygen\bin\doxygen.exe" ${{ github.workspace }}\tools\ci_build\github\Doxyfile_csharp.cfg + shell: cmd + working-directory: ${{ github.workspace }} + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + env: + PROCESSOR_ARCHITECTURE: x64 + with: + dotnet-version: "8.x" + + - name: Use Nuget 6.x + uses: nuget/setup-nuget@v2 + with: + nuget-version: "6.x" + + - name: NuGet restore + run: | + nuget restore packages.config -ConfigFile NuGet.config -PackagesDirectory ${{ github.workspace }}\RelWithDebInfo + shell: cmd + working-directory: ${{ github.workspace }} + + - uses: actions/cache@v4 + id: onnx-node-tests-cache + with: + path: ${{ github.workspace }}/js/test/ + key: onnxnodetests-${{ hashFiles('js/scripts/prepare-onnx-node-tests.ts') }} + + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Build and Test + shell: pwsh + run: | + python.exe ${{ github.workspace }}\tools\ci_build\build.py --config RelWithDebInfo --build_dir ${{ github.workspace }} --skip_submodule_sync --build_csharp --parallel --use_binskim_compliant_compile_flags --cmake_generator "Visual Studio 17 2022" --build_shared_lib --enable_onnx_tests --build_nodejs --use_webgpu --cmake_extra_defines onnxruntime_BUILD_UNIT_TESTS=ON onnxruntime_BUILD_DAWN_MONOLITHIC_LIBRARY=ON + if ($lastExitCode -ne 0) { + exit $lastExitCode + } + Remove-Item "${{ github.workspace }}\RelWithDebInfo" -Include "*.obj" -Recurse + + - name: Run tests (onnxruntime_test_all) with verbose logging + shell: pwsh + run: | + $env:ORT_UNIT_TEST_MAIN_LOG_LEVEL = "0" + .\onnxruntime_test_all.exe 2>.\onnxruntime_test_all_stderr.log + working-directory: ${{ github.workspace }}\RelWithDebInfo\RelWithDebInfo + + - name: Check log file + shell: cmd + run: | + dir ${{ github.workspace }}\RelWithDebInfo\RelWithDebInfo\onnxruntime_test_all_stderr.log + + - name: Validate shader keys + uses: ./.github/actions/webgpu-validate-shader-key + with: + log_file_path: ${{ github.workspace }}\RelWithDebInfo\RelWithDebInfo\onnxruntime_test_all_stderr.log + + - name: Validate C# native delegates + run: python tools\ValidateNativeDelegateAttributes.py + shell: cmd + working-directory: ${{ github.workspace }}\csharp + continue-on-error: true + + webgpu_external_dawn_build_x64_RelWithDebInfo: + runs-on: ["self-hosted", "1ES.Pool=onnxruntime-github-Win2022-GPU-A10"] + timeout-minutes: 300 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: none + + - name: Setup Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + architecture: x64 + + - name: Locate vcvarsall and Setup Env + uses: ./.github/actions/locate-vcvarsall-and-setup-env + with: + architecture: x64 + + - name: Install python modules + run: python -m pip install -r tools\ci_build\github\windows\python\requirements.txt + shell: cmd + working-directory: ${{ github.workspace }} + + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Generate onnxruntime.sln + shell: pwsh + run: | + python.exe ${{ github.workspace }}\tools\ci_build\build.py --config RelWithDebInfo --build_dir ${{ github.workspace }} --skip_submodule_sync --update --parallel --cmake_generator "Visual Studio 17 2022" --use_webgpu --use_external_dawn --skip_tests --target onnxruntime_webgpu_external_dawn_test + + - name: Build + shell: pwsh + run: | + python.exe ${{ github.workspace }}\tools\ci_build\build.py --config RelWithDebInfo --build_dir ${{ github.workspace }} --skip_submodule_sync --build --parallel --cmake_generator "Visual Studio 17 2022" --use_webgpu --use_external_dawn --skip_tests --target onnxruntime_webgpu_external_dawn_test + + - name: Run tests (onnxruntime_webgpu_external_dawn_test) + run: onnxruntime_webgpu_external_dawn_test.exe + shell: cmd + working-directory: ${{ github.workspace }}\RelWithDebInfo\RelWithDebInfo + + - name: Run tests (onnxruntime_webgpu_external_dawn_test) - no_proc_table + run: onnxruntime_webgpu_external_dawn_test.exe --no_proc_table + shell: cmd + working-directory: ${{ github.workspace }}\RelWithDebInfo\RelWithDebInfo + + webgpu_minimal_build_edge_build_x64_RelWithDebInfo: + runs-on: ["self-hosted", "1ES.Pool=onnxruntime-github-Win2022-GPU-A10"] + timeout-minutes: 300 + env: + OrtPackageId: Microsoft.ML.OnnxRuntime + OnnxRuntimeBuildDirectory: ${{ github.workspace }} + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + ALLOW_RELEASED_ONNX_OPSET_ONLY: "0" + DocUpdateNeeded: false + ONNXRUNTIME_TEST_GPU_DEVICE_ID: "0" + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: none + + - name: Setup Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + architecture: x64 + + - name: Locate vcvarsall and Setup Env + uses: ./.github/actions/locate-vcvarsall-and-setup-env + with: + architecture: x64 + + - name: Install python modules + run: python -m pip install -r tools\ci_build\github\windows\python\requirements.txt + shell: cmd + working-directory: ${{ github.workspace }} + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20.x" + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: "17" + architecture: x64 + + - name: API Documentation Check and generate + run: | + set ORT_DOXY_SRC=${{ github.workspace }} + set ORT_DOXY_OUT=${{ github.workspace }}\RelWithDebInfo\RelWithDebInfo + mkdir %ORT_DOXY_SRC% + mkdir %ORT_DOXY_OUT% + "C:\Program Files\doxygen\bin\doxygen.exe" ${{ github.workspace }}\tools\ci_build\github\Doxyfile_csharp.cfg + shell: cmd + working-directory: ${{ github.workspace }} + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + env: + PROCESSOR_ARCHITECTURE: x64 + with: + dotnet-version: "8.x" + + - name: Use Nuget 6.x + uses: nuget/setup-nuget@v2 + with: + nuget-version: "6.x" + + - name: NuGet restore + run: | + nuget restore packages.config -ConfigFile NuGet.config -PackagesDirectory ${{ github.workspace }}\RelWithDebInfo + shell: cmd + working-directory: ${{ github.workspace }} + + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Build + shell: pwsh + run: | + python.exe ${{ github.workspace }}\tools\ci_build\build.py --config RelWithDebInfo --build_dir ${{ github.workspace }} --skip_submodule_sync --build_csharp --parallel --use_binskim_compliant_compile_flags --cmake_generator "Visual Studio 17 2022" --build_shared_lib --update --build --build_shared_lib --disable_exceptions --disable_rtti --enable_msvc_static_runtime --enable_reduced_operator_type_support --skip_tests --use_binskim_compliant_compile_flags --cmake_extra_defines onnxruntime_BUILD_UNIT_TESTS=OFF onnxruntime_DISABLE_SPARSE_TENSORS=ON onnxruntime_DISABLE_OPTIONAL_TYPE=ON --minimal_build extended --use_webgpu + if ($lastExitCode -ne 0) { + exit $lastExitCode + } + Remove-Item "${{ github.workspace }}\RelWithDebInfo" -Include "*.obj" -Recurse + + - name: Validate C# native delegates + run: python tools\ValidateNativeDelegateAttributes.py + shell: cmd + working-directory: ${{ github.workspace }}\csharp diff --git a/.github/workflows/windows_x64_debug_build_x64_debug.yml b/.github/workflows/windows_x64_debug_build_x64_debug.yml new file mode 100644 index 0000000000000..effb6037f695c --- /dev/null +++ b/.github/workflows/windows_x64_debug_build_x64_debug.yml @@ -0,0 +1,135 @@ +name: windows_x64_debug + +on: + push: + branches: [ main, 'rel-*'] + pull_request: + branches: [ main ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build_x64_debug: + runs-on: ["self-hosted", "1ES.Pool=onnxruntime-github-vs2022-mms"] + timeout-minutes: 300 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: false + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + architecture: x64 + + - name: Locate vcvarsall and Setup Env + uses: ./.github/actions/locate-vcvarsall-and-setup-env # Use the composite action + with: + architecture: x64 + + - name: Install python modules + shell: cmd + run: python -m pip install -r "${{ github.workspace }}\tools\ci_build\github\windows\python\requirements.txt" + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + architecture: x64 + + - name: API Documentation Check and generate + shell: cmd + run: | + set ORT_DOXY_SRC=${{ github.workspace }} + set ORT_DOXY_OUT=${{ github.workspace }}\build\Debug\Debug + mkdir %ORT_DOXY_SRC% + mkdir %ORT_DOXY_OUT% + "C:\Program Files\doxygen\bin\doxygen.exe" ${{ github.workspace }}\tools\ci_build\github\Doxyfile_csharp.cfg + working-directory: ${{ github.workspace }} + + - name: Use .NET 8.x + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.x' + env: + PROCESSOR_ARCHITECTURE: x64 + + - name: Use Nuget 6.x + uses: nuget/setup-nuget@v2 # Use the official NuGet setup action + with: + nuget-version: '6.x' + + - name: NuGet restore + shell: cmd + run: | + nuget restore ${{ github.workspace }}\packages.config -PackagesDirectory ${{ github.workspace }}\build\Debug -ConfigFile ${{ github.workspace }}\NuGet.config + + - uses: actions/cache@v4 + id: onnx-node-tests-cache + with: + path: ${{ github.workspace }}/js/test/ + key: onnxnodetests-${{ hashFiles('js/scripts/prepare-onnx-node-tests.ts') }} + + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Build and Test + shell: pwsh + run: | + python.exe "${{ github.workspace }}\tools\ci_build\build.py" --config Debug --build_dir "${{ github.workspace }}\build" --skip_submodule_sync --build_csharp --parallel --use_binskim_compliant_compile_flags --cmake_generator "Visual Studio 17 2022" --build_shared_lib --enable_onnx_tests --build_java --build_nodejs --build_wheel --disable_memleak_checker --msbuild_extra_options "IncludeMobileTargets=false" --build_nuget --use_vcpkg --use_vcpkg_ms_internal_asset_cache + if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE + } + Remove-Item "${{ github.workspace }}\build\Debug" -Include "*.obj" -Recurse + env: # Set environment variables here, applies to this step only + ALLOW_RELEASED_ONNX_OPSET_ONLY: '0' + DocUpdateNeeded: 'false' # Can be set dynamically based on build output if needed + + + - name: Validate C# native delegates + shell: cmd + run: python tools\ValidateNativeDelegateAttributes.py + working-directory: ${{ github.workspace }}\\csharp + + - name: Install onnxruntime wheel + shell: pwsh + run: | + python -m pip uninstall -y onnxruntime onnxruntime-gpu onnxruntime-training onnxruntime-directml -qq + Get-ChildItem -Path dist/*.whl | foreach {pip --disable-pip-version-check install --upgrade $_.fullname} + working-directory: "${{ github.workspace }}\\build\\Debug\\Debug" + + # Publish artifacts only on failure and if DocUpdateNeeded is true (example) + - name: Publish OperatorKernels.md (Conditional) + uses: actions/upload-artifact@v4 + if: failure() && env.DocUpdateNeeded == 'true' # Use env. for step-level vars + with: + name: OperatorKernels.md + path: ${{ github.workspace }}/docs/OperatorKernels.md + + - name: Publish ContribOperators.md (Conditional) + uses: actions/upload-artifact@v4 + if: failure() && env.DocUpdateNeeded == 'true' + with: + name: ContribOperators.md + path: ${{ github.workspace }}/docs/ContribOperators.md + + # These variables will persist for the entire job + env: + OrtPackageId: Microsoft.ML.OnnxRuntime + OnnxRuntimeBuildDirectory: ${{ github.workspace }}\build + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 'true' diff --git a/.github/workflows/windows_x64_release_build_x64_release.yml b/.github/workflows/windows_x64_release_build_x64_release.yml new file mode 100644 index 0000000000000..c057997b7275e --- /dev/null +++ b/.github/workflows/windows_x64_release_build_x64_release.yml @@ -0,0 +1,132 @@ +name: windows_x64_release + +on: + push: + branches: [ main, 'rel-*'] + pull_request: + branches: [ main ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build_x64_release: + runs-on: ["self-hosted", "1ES.Pool=onnxruntime-github-vs2022-mms"] + timeout-minutes: 300 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: false + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + architecture: x64 + + - name: Locate vcvarsall and Setup Env + uses: ./.github/actions/locate-vcvarsall-and-setup-env + with: + architecture: x64 + + - name: Install python modules + shell: cmd + run: python -m pip install -r "${{ github.workspace }}\tools\ci_build\github\windows\python\requirements.txt" + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + architecture: x64 + + - name: API Documentation Check and generate + shell: cmd + run: | + set ORT_DOXY_SRC=${{ github.workspace }} + set ORT_DOXY_OUT=${{ github.workspace }}\build\RelWithDebInfo\RelWithDebInfo + mkdir %ORT_DOXY_SRC% + mkdir %ORT_DOXY_OUT% + "C:\Program Files\doxygen\bin\doxygen.exe" ${{ github.workspace }}\tools\ci_build\github\Doxyfile_csharp.cfg + working-directory: ${{ github.workspace }} + + - name: Use .NET 8.x + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.x' + env: + PROCESSOR_ARCHITECTURE: x64 + + - name: Use Nuget 6.x + uses: nuget/setup-nuget@v2 + with: + nuget-version: '6.x' + + - name: NuGet restore + shell: cmd + run: | + nuget restore ${{ github.workspace }}\packages.config -PackagesDirectory ${{ github.workspace }}\build\RelWithDebInfo -ConfigFile ${{ github.workspace }}\NuGet.config + + - uses: actions/cache@v4 + id: onnx-node-tests-cache + with: + path: ${{ github.workspace }}/js/test/ + key: onnxnodetests-${{ hashFiles('js/scripts/prepare-onnx-node-tests.ts') }} + + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Build and Test + shell: pwsh + run: | + python.exe "${{ github.workspace }}\tools\ci_build\build.py" --config RelWithDebInfo --build_dir "${{ github.workspace }}\build" --skip_submodule_sync --build_csharp --parallel --use_binskim_compliant_compile_flags --cmake_generator "Visual Studio 17 2022" --build_shared_lib --enable_onnx_tests --build_wheel --build_java --build_nodejs --msbuild_extra_options "IncludeMobileTargets=false" --build_nuget --use_vcpkg --use_vcpkg_ms_internal_asset_cache + if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE + } + Remove-Item "${{ github.workspace }}\build\RelWithDebInfo" -Include "*.obj" -Recurse + env: + ALLOW_RELEASED_ONNX_OPSET_ONLY: '0' + DocUpdateNeeded: 'false' + + - name: Validate C# native delegates + shell: cmd + run: python tools\ValidateNativeDelegateAttributes.py + working-directory: ${{ github.workspace }}\\csharp + + - name: Install onnxruntime wheel + shell: pwsh + run: | + python -m pip uninstall -y onnxruntime onnxruntime-gpu onnxruntime-training onnxruntime-directml -qq + Get-ChildItem -Path dist/*.whl | foreach {pip --disable-pip-version-check install --upgrade $_.fullname} + working-directory: "${{ github.workspace }}\\build\\RelWithDebInfo\\RelWithDebInfo" + + - name: Publish OperatorKernels.md (Conditional) + uses: actions/upload-artifact@v4 + if: failure() && env.DocUpdateNeeded == 'true' + with: + name: OperatorKernels.md + path: ${{ github.workspace }}/docs/OperatorKernels.md + + - name: Publish ContribOperators.md (Conditional) + uses: actions/upload-artifact@v4 + if: failure() && env.DocUpdateNeeded == 'true' + with: + name: ContribOperators.md + path: ${{ github.workspace }}/docs/ContribOperators.md + + env: + OrtPackageId: Microsoft.ML.OnnxRuntime + OnnxRuntimeBuildDirectory: ${{ github.workspace }}\build + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 'true' diff --git a/.github/workflows/windows_x64_release_dnnl_build_x64_release.yml b/.github/workflows/windows_x64_release_dnnl_build_x64_release.yml new file mode 100644 index 0000000000000..5e83a0dd54dfb --- /dev/null +++ b/.github/workflows/windows_x64_release_dnnl_build_x64_release.yml @@ -0,0 +1,131 @@ +name: windows_x64_dnnl_release + +on: + push: + branches: [ main, 'rel-*'] + pull_request: + branches: [ main ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build_x64_dnnl_release: + runs-on: ["self-hosted", "1ES.Pool=onnxruntime-github-vs2022-mms"] + timeout-minutes: 300 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: false + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + architecture: x64 + + - name: Locate vcvarsall and Setup Env + uses: ./.github/actions/locate-vcvarsall-and-setup-env + with: + architecture: x64 + + - name: Install python modules + shell: cmd + run: python -m pip install -r "${{ github.workspace }}\tools\ci_build\github\windows\python\requirements.txt" + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + architecture: x64 + + - name: API Documentation Check and generate + shell: cmd + run: | + set ORT_DOXY_SRC=${{ github.workspace }} + set ORT_DOXY_OUT=${{ github.workspace }}\build\RelWithDebInfo\RelWithDebInfo + mkdir %ORT_DOXY_SRC% + mkdir %ORT_DOXY_OUT% + "C:\Program Files\doxygen\bin\doxygen.exe" ${{ github.workspace }}\tools\ci_build\github\Doxyfile_csharp.cfg + working-directory: ${{ github.workspace }} + + - name: Use .NET 8.x + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.x' + env: + PROCESSOR_ARCHITECTURE: x64 + + - name: Use Nuget 6.x + uses: nuget/setup-nuget@v2 + with: + nuget-version: '6.x' + + - name: NuGet restore + shell: cmd + run: | + nuget restore ${{ github.workspace }}\packages.config -PackagesDirectory ${{ github.workspace }}\build\RelWithDebInfo -ConfigFile ${{ github.workspace }}\NuGet.config + + - uses: actions/cache@v4 + id: onnx-node-tests-cache + with: + path: ${{ github.workspace }}/js/test/ + key: onnxnodetests-${{ hashFiles('js/scripts/prepare-onnx-node-tests.ts') }} + + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Build and Test + shell: pwsh + run: | + python.exe "${{ github.workspace }}\tools\ci_build\build.py" --config RelWithDebInfo --build_dir "${{ github.workspace }}\build" --skip_submodule_sync --build_csharp --parallel --use_binskim_compliant_compile_flags --cmake_generator "Visual Studio 17 2022" --build_shared_lib --enable_onnx_tests --build_wheel --build_java --build_nodejs --msbuild_extra_options "IncludeMobileTargets=false" --build_nuget --use_vcpkg --use_vcpkg_ms_internal_asset_cache --use_dnnl + if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE + } + Remove-Item "${{ github.workspace }}\build\RelWithDebInfo" -Include "*.obj" -Recurse + env: + ALLOW_RELEASED_ONNX_OPSET_ONLY: '0' + + - name: Validate C# native delegates + shell: cmd + run: python tools\ValidateNativeDelegateAttributes.py + working-directory: ${{ github.workspace }}\\csharp + + - name: Install onnxruntime wheel + shell: pwsh + run: | + python -m pip uninstall -y onnxruntime onnxruntime-gpu onnxruntime-training onnxruntime-directml -qq + Get-ChildItem -Path dist/*.whl | foreach {pip --disable-pip-version-check install --upgrade $_.fullname} + working-directory: "${{ github.workspace }}\\build\\RelWithDebInfo\\RelWithDebInfo" + + - name: Publish OperatorKernels.md (Conditional) + uses: actions/upload-artifact@v4 + if: failure() && env.DocUpdateNeeded == 'true' + with: + name: OperatorKernels.md + path: ${{ github.workspace }}/docs/OperatorKernels.md + + - name: Publish ContribOperators.md (Conditional) + uses: actions/upload-artifact@v4 + if: failure() && env.DocUpdateNeeded == 'true' + with: + name: ContribOperators.md + path: ${{ github.workspace }}/docs/ContribOperators.md + + env: + OrtPackageId: Microsoft.ML.OnnxRuntime + OnnxRuntimeBuildDirectory: ${{ github.workspace }}\build + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 'true' diff --git a/.github/workflows/windows_x64_release_ep_generic_interface_build_x64_release_ep_generic_interface.yml b/.github/workflows/windows_x64_release_ep_generic_interface_build_x64_release_ep_generic_interface.yml new file mode 100644 index 0000000000000..a0bf348a7dba0 --- /dev/null +++ b/.github/workflows/windows_x64_release_ep_generic_interface_build_x64_release_ep_generic_interface.yml @@ -0,0 +1,117 @@ +name: windows_x64_release_ep_generic_interface + +on: + push: + branches: [ main, 'rel-*'] + pull_request: + branches: [ main ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build_x64_release_ep_generic_interface: + runs-on: ["self-hosted", "1ES.Pool=onnxruntime-github-vs2022-mms"] + timeout-minutes: 300 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: false + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + architecture: x64 + + - name: Locate vcvarsall and Setup Env + uses: ./.github/actions/locate-vcvarsall-and-setup-env + with: + architecture: x64 + + - name: Install python modules + shell: cmd + run: python -m pip install -r "${{ github.workspace }}\tools\ci_build\github\windows\python\requirements.txt" + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + architecture: x64 + + - name: API Documentation Check and generate + shell: cmd + run: | + set ORT_DOXY_SRC=${{ github.workspace }} + set ORT_DOXY_OUT=${{ github.workspace }}\build\RelWithDebInfo\RelWithDebInfo + mkdir %ORT_DOXY_SRC% + mkdir %ORT_DOXY_OUT% + "C:\Program Files\doxygen\bin\doxygen.exe" ${{ github.workspace }}\tools\ci_build\github\Doxyfile_csharp.cfg + working-directory: ${{ github.workspace }} + + - name: Use .NET 8.x + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.x' + env: + PROCESSOR_ARCHITECTURE: x64 + + - name: Use Nuget 6.x + uses: nuget/setup-nuget@v2 + with: + nuget-version: '6.x' + + - name: NuGet restore + shell: cmd + run: | + nuget restore ${{ github.workspace }}\packages.config -PackagesDirectory ${{ github.workspace }}\build\RelWithDebInfo -ConfigFile ${{ github.workspace }}\NuGet.config + + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Build + shell: pwsh + run: | + python.exe "${{ github.workspace }}\tools\ci_build\build.py" --config RelWithDebInfo --build_dir "${{ github.workspace }}\build" --skip_submodule_sync --build_csharp --parallel --use_binskim_compliant_compile_flags --cmake_generator "Visual Studio 17 2022" --build_shared_lib --update --build --enable_generic_interface --use_vcpkg --use_vcpkg_ms_internal_asset_cache + if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE + } + Remove-Item "${{ github.workspace }}\build\RelWithDebInfo" -Include "*.obj" -Recurse + env: + ALLOW_RELEASED_ONNX_OPSET_ONLY: '0' + + - name: Validate C# native delegates + shell: cmd + run: python tools\ValidateNativeDelegateAttributes.py + working-directory: ${{ github.workspace }}\\csharp + - name: Publish OperatorKernels.md (Conditional) + uses: actions/upload-artifact@v4 + if: failure() && env.DocUpdateNeeded == 'true' + with: + name: OperatorKernels.md + path: ${{ github.workspace }}/docs/OperatorKernels.md + + - name: Publish ContribOperators.md (Conditional) + uses: actions/upload-artifact@v4 + if: failure() && env.DocUpdateNeeded == 'true' + with: + name: ContribOperators.md + path: ${{ github.workspace }}/docs/ContribOperators.md + + env: + OrtPackageId: Microsoft.ML.OnnxRuntime + OnnxRuntimeBuildDirectory: ${{ github.workspace }}\build + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 'true' diff --git a/.github/workflows/windows_x64_release_vitisai_build_x64_release.yml b/.github/workflows/windows_x64_release_vitisai_build_x64_release.yml new file mode 100644 index 0000000000000..0ef97f07a0fe9 --- /dev/null +++ b/.github/workflows/windows_x64_release_vitisai_build_x64_release.yml @@ -0,0 +1,113 @@ +name: windows_x64_release_vitisai + +on: + push: + branches: [ main, 'rel-*'] + pull_request: + branches: [ main ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build_x64_release_vitisai: + runs-on: ["self-hosted", "1ES.Pool=onnxruntime-github-vs2022-mms"] + timeout-minutes: 300 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: false + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + architecture: x64 + + - name: Locate vcvarsall and Setup Env + uses: ./.github/actions/locate-vcvarsall-and-setup-env + with: + architecture: x64 + + - name: Install python modules + shell: cmd + run: python -m pip install -r "${{ github.workspace }}\tools\ci_build\github\windows\python\requirements.txt" + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + architecture: x64 + + - name: API Documentation Check and generate + shell: cmd + run: | + set ORT_DOXY_SRC=${{ github.workspace }} + set ORT_DOXY_OUT=${{ github.workspace }}\build\RelWithDebInfo\RelWithDebInfo + mkdir %ORT_DOXY_SRC% + mkdir %ORT_DOXY_OUT% + "C:\Program Files\doxygen\bin\doxygen.exe" ${{ github.workspace }}\tools\ci_build\github\Doxyfile_csharp.cfg + working-directory: ${{ github.workspace }} + + - name: Use .NET 8.x + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.x' + env: + PROCESSOR_ARCHITECTURE: x64 + + - name: Use Nuget 6.x + uses: nuget/setup-nuget@v2 + with: + nuget-version: '6.x' + + - name: NuGet restore + shell: cmd + run: | + nuget restore ${{ github.workspace }}\packages.config -PackagesDirectory ${{ github.workspace }}\build\RelWithDebInfo -ConfigFile ${{ github.workspace }}\NuGet.config + + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Build + shell: pwsh + run: | + python.exe "${{ github.workspace }}\tools\ci_build\build.py" --config RelWithDebInfo --build_dir "${{ github.workspace }}\build" --skip_submodule_sync --build_csharp --parallel --use_binskim_compliant_compile_flags --cmake_generator "Visual Studio 17 2022" --build_shared_lib --update --build --build_wheel --use_vitisai --use_vcpkg --use_vcpkg_ms_internal_asset_cache + if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE + } + Remove-Item "${{ github.workspace }}\build\RelWithDebInfo" -Include "*.obj" -Recurse + env: + ALLOW_RELEASED_ONNX_OPSET_ONLY: '0' + + - name: Validate C# native delegates + shell: cmd + run: python tools\ValidateNativeDelegateAttributes.py + working-directory: ${{ github.workspace }}\\csharp + + - name: Install onnxruntime wheel + shell: pwsh + run: | + python -m pip uninstall -y onnxruntime onnxruntime-gpu onnxruntime-training onnxruntime-directml -qq + if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE + } + Get-ChildItem -Path dist/*.whl | foreach {pip --disable-pip-version-check install --upgrade $_.fullname} + working-directory: "${{ github.workspace }}\\build\\RelWithDebInfo\\RelWithDebInfo" + env: + OrtPackageId: Microsoft.ML.OnnxRuntime + OnnxRuntimeBuildDirectory: ${{ github.workspace }}\build + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 'true' diff --git a/.github/workflows/windows_x64_release_xnnpack.yml b/.github/workflows/windows_x64_release_xnnpack.yml new file mode 100644 index 0000000000000..970f94371b905 --- /dev/null +++ b/.github/workflows/windows_x64_release_xnnpack.yml @@ -0,0 +1,119 @@ +name: windows_x64_release_xnnpack + +on: + push: + branches: [ main, 'rel-*'] + pull_request: + branches: [ main ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build_x64_release_xnnpack: + runs-on: ["self-hosted", "1ES.Pool=onnxruntime-github-vs2022-mms"] + timeout-minutes: 300 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: false + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + architecture: x64 + + - name: Locate vcvarsall and Setup Env + uses: ./.github/actions/locate-vcvarsall-and-setup-env + with: + architecture: x64 + + - name: Install python modules + shell: cmd + run: python -m pip install -r "${{ github.workspace }}\tools\ci_build\github\windows\python\requirements.txt" + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + architecture: x64 + + - name: API Documentation Check and generate + shell: cmd + run: | + set ORT_DOXY_SRC=${{ github.workspace }} + set ORT_DOXY_OUT=${{ github.workspace }}\build\RelWithDebInfo\RelWithDebInfo + mkdir %ORT_DOXY_SRC% + mkdir %ORT_DOXY_OUT% + "C:\Program Files\doxygen\bin\doxygen.exe" ${{ github.workspace }}\tools\ci_build\github\Doxyfile_csharp.cfg + working-directory: ${{ github.workspace }} + + - name: Use .NET 8.x + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.x' + env: + PROCESSOR_ARCHITECTURE: x64 + + - name: Use Nuget 6.x + uses: nuget/setup-nuget@v2 + with: + nuget-version: '6.x' + + - name: NuGet restore + shell: cmd + run: | + nuget restore ${{ github.workspace }}\packages.config -PackagesDirectory ${{ github.workspace }}\build\RelWithDebInfo -ConfigFile ${{ github.workspace }}\NuGet.config + + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Build and Test + shell: pwsh + run: | + python.exe "${{ github.workspace }}\tools\ci_build\build.py" --use_xnnpack --config RelWithDebInfo --build_dir "${{ github.workspace }}\build" --skip_submodule_sync --build_csharp --parallel --use_binskim_compliant_compile_flags --cmake_generator "Visual Studio 17 2022" --build_shared_lib --enable_onnx_tests --disable_rtti --msbuild_extra_options "IncludeMobileTargets=false" --build_nuget --use_vcpkg --use_vcpkg_ms_internal_asset_cache + if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE + } + Remove-Item "${{ github.workspace }}\build\RelWithDebInfo" -Include "*.obj" -Recurse + env: + ALLOW_RELEASED_ONNX_OPSET_ONLY: '0' + DocUpdateNeeded: 'false' + + - name: Validate C# native delegates + shell: cmd + run: python tools\ValidateNativeDelegateAttributes.py + working-directory: ${{ github.workspace }}\\csharp + + - name: Publish OperatorKernels.md (Conditional) + uses: actions/upload-artifact@v4 + if: failure() && env.DocUpdateNeeded == 'true' + with: + name: OperatorKernels.md + path: ${{ github.workspace }}/docs/OperatorKernels.md + + - name: Publish ContribOperators.md (Conditional) + uses: actions/upload-artifact@v4 + if: failure() && env.DocUpdateNeeded == 'true' + with: + name: ContribOperators.md + path: ${{ github.workspace }}/docs/ContribOperators.md + + env: + OrtPackageId: Microsoft.ML.OnnxRuntime + OnnxRuntimeBuildDirectory: ${{ github.workspace }}\build + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 'true' diff --git a/.github/workflows/windows_x86.yml b/.github/workflows/windows_x86.yml new file mode 100644 index 0000000000000..2819123e47670 --- /dev/null +++ b/.github/workflows/windows_x86.yml @@ -0,0 +1,127 @@ +name: Windows CPU CI Pipeline + +on: + push: + branches: [ main, 'rel-*'] + pull_request: + branches: [ main ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build_x86_release: + runs-on: ["self-hosted", "1ES.Pool=onnxruntime-github-vs2022-mms"] + timeout-minutes: 300 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: false + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + architecture: x86 # x86 Python + + - name: Locate vcvarsall and Setup Env + uses: ./.github/actions/locate-vcvarsall-and-setup-env + with: + architecture: x86 # x86 architecture for vcvarsall + + - name: Install python modules + shell: cmd + run: python -m pip install -r "${{ github.workspace }}\tools\ci_build\github\windows\python\requirements.txt" + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + architecture: x86 #Add architecture + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + architecture: x86 # x86 Java + + - name: API Documentation Check and generate + shell: cmd + run: | + set ORT_DOXY_SRC=${{ github.workspace }} + set ORT_DOXY_OUT=${{ github.workspace }}\build\RelWithDebInfo\RelWithDebInfo + mkdir %ORT_DOXY_SRC% + mkdir %ORT_DOXY_OUT% + "C:\Program Files\doxygen\bin\doxygen.exe" ${{ github.workspace }}\tools\ci_build\github\Doxyfile_csharp.cfg + working-directory: ${{ github.workspace }} + + - name: Use .NET 8.x + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.x' + env: + PROCESSOR_ARCHITECTURE: x86 # x86 .NET + + - name: Use Nuget 6.x + uses: nuget/setup-nuget@v2 + with: + nuget-version: '6.x' + + - name: NuGet restore + shell: cmd + run: | + nuget restore ${{ github.workspace }}\packages.config -PackagesDirectory ${{ github.workspace }}\build\RelWithDebInfo -ConfigFile ${{ github.workspace }}\NuGet.config + + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Build and Test + shell: pwsh + run: | + python.exe "${{ github.workspace }}\tools\ci_build\build.py" --config RelWithDebInfo --build_dir "${{ github.workspace }}\build" --skip_submodule_sync --build_csharp --parallel --use_binskim_compliant_compile_flags --cmake_generator "Visual Studio 17 2022" --build_shared_lib --enable_onnx_tests --build_wheel --msbuild_extra_options "IncludeMobileTargets=false" --build_nuget --use_vcpkg --use_vcpkg_ms_internal_asset_cache + if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE + } + Remove-Item "${{ github.workspace }}\build\RelWithDebInfo" -Include "*.obj" -Recurse + env: + ALLOW_RELEASED_ONNX_OPSET_ONLY: '0' + DocUpdateNeeded: 'false' + + - name: Validate C# native delegates + shell: cmd + run: python tools\ValidateNativeDelegateAttributes.py + working-directory: ${{ github.workspace }}\\csharp + + - name: Install onnxruntime wheel + shell: pwsh + run: | + python -m pip uninstall -y onnxruntime onnxruntime-gpu onnxruntime-training onnxruntime-directml -qq + Get-ChildItem -Path dist/*.whl | foreach {pip --disable-pip-version-check install --upgrade $_.fullname} + working-directory: "${{ github.workspace }}\\build\\RelWithDebInfo\\RelWithDebInfo" + + - name: Publish OperatorKernels.md (Conditional) + uses: actions/upload-artifact@v4 + if: failure() && env.DocUpdateNeeded == 'true' + with: + name: OperatorKernels.md + path: ${{ github.workspace }}/docs/OperatorKernels.md + + - name: Publish ContribOperators.md (Conditional) + uses: actions/upload-artifact@v4 + if: failure() && env.DocUpdateNeeded == 'true' + with: + name: ContribOperators.md + path: ${{ github.workspace }}/docs/ContribOperators.md + + env: + OrtPackageId: Microsoft.ML.OnnxRuntime + OnnxRuntimeBuildDirectory: ${{ github.workspace }}\build + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 'true' diff --git a/.gitmodules b/.gitmodules index 356447cbf7a98..7656fc429d005 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,4 +7,4 @@ [submodule "cmake/external/emsdk"] path = cmake/external/emsdk url = https://github.com/emscripten-core/emsdk.git - branch = 4.0.3 + branch = 4.0.4 diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index a449e42f6bf19..7b2bbdd2094d1 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -6080,3 +6080,77 @@ https://dawn.googlesource.com/dawn CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +_____ + +KleidiAI + +https://gitlab.arm.com/kleidi/kleidiai + +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +Copyright 2024-2025 Arm Limited and/or its affiliates + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/VERSION_NUMBER b/VERSION_NUMBER index 3500250a4b05b..57807d6d0d0c0 100644 --- a/VERSION_NUMBER +++ b/VERSION_NUMBER @@ -1 +1 @@ -1.21.0 +1.22.0 diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 2714e6f59dbac..b8c9abcf344e5 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -55,10 +55,6 @@ if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Choose build type: Debug Release RelWithDebInfo MinSizeRel." FORCE) endif() -if("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 9) - message(FATAL_ERROR "GCC version must be greater than or equal to 9") -endif() - # Options option(onnxruntime_USE_VCPKG "Build with the vcpkg package manager" OFF) option(onnxruntime_RUN_ONNX_TESTS "Enable ONNX Compatibility Testing" OFF) @@ -87,6 +83,7 @@ option(onnxruntime_USE_SNPE "Build with SNPE support" OFF) option(onnxruntime_USE_RKNPU "Build with RKNPU support" OFF) option(onnxruntime_USE_DNNL "Build with DNNL support" OFF) option(onnxruntime_USE_JSEP "Build with JavaScript implemented kernels support" OFF) +option(onnxruntime_USE_KLEIDIAI "Build with KleidiAI integration in MLAS" OFF) option(onnxruntime_BUILD_UNIT_TESTS "Build ONNXRuntime unit tests" ON) option(onnxruntime_BUILD_CSHARP "Build C# library" OFF) option(onnxruntime_BUILD_OBJC "Build Objective-C library" OFF) @@ -196,6 +193,7 @@ option(onnxruntime_ENABLE_WEBASSEMBLY_DEBUG_INFO "Enable this option to turn on option(onnxruntime_ENABLE_WEBASSEMBLY_PROFILING "Enable this option to turn on WebAssembly profiling and preserve function names" OFF) option(onnxruntime_ENABLE_WEBASSEMBLY_OUTPUT_OPTIMIZED_MODEL "Enable this option to allow WebAssembly to output optimized model" OFF) option(onnxruntime_ENABLE_WEBASSEMBLY_MEMORY64 "Enable this option to allow WebAssembly to use 64bit memory" OFF) +option(onnxruntime_ENABLE_WEBASSEMBLY_RELAXED_SIMD "Enable WebAssembly Relaxed SIMD" OFF) # Enable bitcode for iOS option(onnxruntime_ENABLE_BITCODE "Enable bitcode for iOS only" OFF) @@ -258,6 +256,11 @@ option(onnxruntime_USE_OPENVINO_INTERFACE "Build ONNXRuntime shared lib which is option(onnxruntime_USE_VITISAI_INTERFACE "Build ONNXRuntime shared lib which is compatible with Vitis-AI EP interface" OFF) option(onnxruntime_USE_QNN_INTERFACE "Build ONNXRuntime shared lib which is compatible with QNN EP interface" OFF) + +if("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 11.1) + message(FATAL_ERROR "GCC version must be greater than or equal to 11.1") +endif() + # ENABLE_TRAINING includes all training functionality # The following 2 entry points # 1. ORTModule @@ -831,6 +834,20 @@ else() endif() endif() +if (onnxruntime_USE_KLEIDIAI AND NOT MSVC AND ( + (onnxruntime_target_platform STREQUAL "aarch64") OR + (onnxruntime_target_platform STREQUAL "ARM64") OR + (APPLE AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64"))) + check_cxx_compiler_flag(-march=armv8.2-a+dotprod HAS_ARM64_DOTPROD) + check_cxx_compiler_flag(-march=armv8.2-a+i8mm HAS_ARM64_I8MM) + if (NOT HAS_ARM64_DOTPROD) + message(FATAL_ERROR "The compiler doesn't support dotprod") + endif() + if (NOT HAS_ARM64_I8MM) + message(FATAL_ERROR "The compiler doesn't support i8mm") + endif() +endif() + #names in this var must match the directory names under onnxruntime/core/providers #ONNXRUNTIME_PROVIDER_NAMES is the list of providers that needs to export additional symbols in the global namespace. #For example CUDA EP exports "OrtSessionOptionsAppendExecutionProvider_CUDA", which is a global function. @@ -1250,6 +1267,7 @@ function(onnxruntime_set_compile_flags target_name) # Unsupported by Clang 18 yet. list(REMOVE_ITEM ORT_HIP_WARNING_FLAGS -Wno-dangling-reference) + list(REMOVE_ITEM ORT_HIP_WARNING_FLAGS -Wno-interference-size) # float16.h:90:12: error: ‘tmp’ is used uninitialized list(APPEND ORT_HIP_WARNING_FLAGS -Wno-uninitialized) list(APPEND ORT_HIP_WARNING_FLAGS -Wno-deprecated-copy) @@ -1512,6 +1530,11 @@ if (onnxruntime_USE_OPENVINO) endif() +if (onnxruntime_USE_OPENVINO_INTERFACE AND (NOT onnxruntime_USE_OPENVINO)) + add_definitions(-DUSE_OPENVINO=1) + add_definitions(-DOPENVINO_CONFIG_NPU=1) +endif() + if (onnxruntime_USE_VITISAI) set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_LIST_DIR}") endif() @@ -1542,32 +1565,21 @@ if (onnxruntime_USE_CUDA) endif() find_package(CUDAToolkit REQUIRED) if (NOT CMAKE_CUDA_ARCHITECTURES) + # Note that we generate SASS+PTX code for specified cuda architectures by assigning "xy" + # To add SASS only, assign "xy-real" + # To add PTX only, assign "xy-virtual" if (CMAKE_LIBRARY_ARCHITECTURE STREQUAL "aarch64-linux-gnu") # Support for Jetson/Tegra ARM devices - set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gencode=arch=compute_53,code=sm_53") # TX1, Nano - set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gencode=arch=compute_62,code=sm_62") # TX2 - set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gencode=arch=compute_72,code=sm_72") # AGX Xavier, NX Xavier - set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gencode=arch=compute_87,code=sm_87") # AGX Orin, NX Orin + set(CMAKE_CUDA_ARCHITECTURES "53-real;62-real;72-real;87") # TX1/Nano, TX2, Xavier, Orin else() if (CMAKE_CUDA_COMPILER_VERSION VERSION_LESS 12) # 37, 50 still work in CUDA 11 but are marked deprecated and will be removed in future CUDA version. - set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gencode=arch=compute_37,code=sm_37") # K80 - set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gencode=arch=compute_50,code=sm_50") # M series - endif() - # Note that we generate SASS code for specified cuda architectures. It does not support forward compatibility. - # To add PTX for future GPU architectures >= XX, append -gencode=arch=compute_XX,code=compute_XX. - set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gencode=arch=compute_52,code=sm_52") # M60 - set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gencode=arch=compute_60,code=sm_60") # P series - set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gencode=arch=compute_70,code=sm_70") # V series - set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gencode=arch=compute_75,code=sm_75") # T series - set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gencode=arch=compute_80,code=sm_80") # A series - set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gencode=arch=compute_86,code=sm_86") - set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gencode=arch=compute_89,code=sm_89") - if (CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 12) - set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gencode=arch=compute_90,code=sm_90") # H series - if (CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 12.8) - set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gencode=arch=compute_120,code=sm_120") # B series - endif() + set(CMAKE_CUDA_ARCHITECTURES "37-real;50-real;52-real;60-real;70-real;75-real;80-real;86-real;89") + elseif (CMAKE_CUDA_COMPILER_VERSION VERSION_LESS 12.8) + set(CMAKE_CUDA_ARCHITECTURES "52-real;60-real;70-real;75-real;80-real;86-real;89-real;90") + else() + # https://cmake.org/cmake/help/latest/prop_tgt/CUDA_ARCHITECTURES.html + set(CMAKE_CUDA_ARCHITECTURES "all") # Supporting all, including latest Blackwell B series & RTX 50 series endif() endif() endif() @@ -1807,8 +1819,8 @@ if (onnxruntime_USE_WINML) endif() # if (onnxruntime_USE_WINML) if (onnxruntime_BUILD_SHARED_LIB OR onnxruntime_BUILD_APPLE_FRAMEWORK) - if (onnxruntime_BUILD_APPLE_FRAMEWORK AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin|iOS|visionOS") - message(FATAL_ERROR "onnxruntime_BUILD_APPLE_FRAMEWORK can only be enabled for macOS or iOS or visionOS.") + if (onnxruntime_BUILD_APPLE_FRAMEWORK AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin|iOS|visionOS|tvOS") + message(FATAL_ERROR "onnxruntime_BUILD_APPLE_FRAMEWORK can only be enabled for macOS or iOS or visionOS or tvOS.") endif() list(APPEND ONNXRUNTIME_CMAKE_FILES onnxruntime) endif() diff --git a/cmake/CMakePresets.json b/cmake/CMakePresets.json index 4987edaf85513..8d63912f6eaee 100644 --- a/cmake/CMakePresets.json +++ b/cmake/CMakePresets.json @@ -109,6 +109,29 @@ "rhs": "Darwin" } }, + { + "name": "arm64-osx", + "inherits": [ + "unit-test" + ], + "generator": "Xcode", + "binaryDir": "${sourceParentDir}/cmake_build/arm64-osx", + "installDir": "${sourceParentDir}/cmake_build/out", + "cacheVariables": { + "CMAKE_OSX_ARCHITECTURES": "arm64", + "onnxruntime_BUILD_SHARED_LIB": true, + "onnxruntime_USE_XNNPACK": false, + "onnxruntime_USE_COREML": true, + "onnxruntime_BUILD_OBJC": true, + "onnxruntime_BUILD_APPLE_FRAMEWORK": true, + "CMAKE_CONFIGURATION_TYPES": "Debug;Release" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Darwin" + } + }, { "name": "x64-osx-vcpkg", "inherits": [ diff --git a/cmake/adjust_global_compile_flags.cmake b/cmake/adjust_global_compile_flags.cmake index 2aa83e9e3ee96..8f5ef15c53ef2 100644 --- a/cmake/adjust_global_compile_flags.cmake +++ b/cmake/adjust_global_compile_flags.cmake @@ -35,7 +35,10 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") set(CMAKE_CXX_FLAGS_DEBUG "-g2") endif() - if (onnxruntime_ENABLE_WEBASSEMBLY_SIMD) + if (onnxruntime_ENABLE_WEBASSEMBLY_RELAXED_SIMD) + string(APPEND CMAKE_C_FLAGS " -msimd128 -mrelaxed-simd") + string(APPEND CMAKE_CXX_FLAGS " -msimd128 -mrelaxed-simd") + elseif (onnxruntime_ENABLE_WEBASSEMBLY_SIMD) string(APPEND CMAKE_C_FLAGS " -msimd128") string(APPEND CMAKE_CXX_FLAGS " -msimd128") endif() @@ -99,10 +102,21 @@ if (onnxruntime_ENABLE_LTO) include(CheckIPOSupported) check_ipo_supported(RESULT ipo_enabled OUTPUT ipo_output) if (NOT ipo_enabled) - message(WARNING "IPO is not supported by this compiler") + message(WARNING "Interprocedural optimization (IPO) is not supported by this compiler. ${ipo_output}") set(onnxruntime_ENABLE_LTO OFF) else() set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) + + # See https://cmake.org/cmake/help/latest/policy/CMP0069.html. + # + # "The OLD behavior for this policy is to add IPO flags only for Intel compiler on Linux. + # The NEW behavior for this policy is to add IPO flags for the current compiler or produce an error if CMake does + # not know the flags." + # + # CMake versions 3.8 and lower use the OLD behavior. This project requires CMake version > 3.8. + # However, some dependencies may specify a lower required CMake version and default to the OLD behavior. + # Ensure that CMake also uses the NEW behavior for such dependencies. + set(CMAKE_POLICY_DEFAULT_CMP0069 NEW) endif() endif() @@ -178,9 +192,9 @@ if (onnxruntime_CROSS_COMPILING) endif() endif() -# Mark symbols to be invisible, for macOS/iOS/visionOS target only +# Mark symbols to be invisible, for macOS/iOS/visionOS/tvOS target only # Due to many dependencies have different symbol visibility settings, set global compile flags here. -if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin|iOS|visionOS") +if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin|iOS|visionOS|tvOS") foreach(flags CMAKE_CXX_FLAGS CMAKE_OBJC_FLAGS CMAKE_OBJCXX_FLAGS) string(APPEND ${flags} " -fvisibility=hidden -fvisibility-inlines-hidden") endforeach() @@ -342,4 +356,4 @@ endif() if (onnxruntime_USE_EXTENSIONS) include_directories(${REPO_ROOT}/include/onnxruntime/core/session) -endif() \ No newline at end of file +endif() diff --git a/cmake/deps.txt b/cmake/deps.txt index d0bab93d3c16f..71218fd049afb 100644 --- a/cmake/deps.txt +++ b/cmake/deps.txt @@ -36,8 +36,8 @@ microsoft_wil;https://github.com/microsoft/wil/archive/refs/tags/v1.0.230629.1.z mimalloc;https://github.com/microsoft/mimalloc/archive/refs/tags/v2.1.1.zip;d5ee7d34223d0567892db5179849939c8769dc41 mp11;https://github.com/boostorg/mp11/archive/refs/tags/boost-1.82.0.zip;9bc9e01dffb64d9e0773b2e44d2f22c51aace063 onnx;https://github.com/onnx/onnx/archive/refs/tags/v1.17.0.zip;13a60ac5217c104139ce0fd024f48628e7bcf5bc -# Use the latest commit of 10.8-GA -onnx_tensorrt;https://github.com/onnx/onnx-tensorrt/archive/c5ca8912f30e9ad630a0ef565e3d5f4bd5e91563.zip;588b294aaa9e84679ed5815cea1d399210ac98c2 +# Use the latest commit of 10.9-GA +onnx_tensorrt;https://github.com/onnx/onnx-tensorrt/archive/d5dce67db7c2e64b07e055571f5ec06f7f254de2.zip;01114d3b67650857281fa50faa2e412130a63b69 protobuf;https://github.com/protocolbuffers/protobuf/archive/refs/tags/v21.12.zip;7cf2733949036c7d52fda017badcab093fe73bfa protoc_win64;https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-win64.zip;b4521f7ada5b260380f94c4bd7f1b7684c76969a protoc_win32;https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-win32.zip;3688010318192c46ce73213cdfb6b3e5656da874 @@ -53,10 +53,9 @@ re2;https://github.com/google/re2/archive/refs/tags/2024-07-02.zip;646e1728269cd safeint;https://github.com/dcleblanc/SafeInt/archive/refs/tags/3.0.28.zip;23f252040ff6cb9f1fd18575b32fa8fb5928daac tensorboard;https://github.com/tensorflow/tensorboard/archive/373eb09e4c5d2b3cc2493f0949dc4be6b6a45e81.zip;67b833913605a4f3f499894ab11528a702c2b381 cutlass;https://github.com/NVIDIA/cutlass/archive/refs/tags/v3.5.1.zip;e49b2b964163d27765a5002d210a2f3c73771835 -utf8_range;https://github.com/protocolbuffers/utf8_range/archive/72c943dea2b9240cd09efde15191e144bc7c7d38.zip;9925739c9debc0efa2adcb194d371a35b6a03156 extensions;https://github.com/microsoft/onnxruntime-extensions/archive/c24b7bab0c12f53da76d0c31b03b9f0f8ec8f3b4.zip;239063aee4946a9af147b473a4c3da78ba7413b4 composable_kernel;https://github.com/ROCmSoftwarePlatform/composable_kernel/archive/204da9c522cebec5220bba52cd3542ebcaf99e7a.zip;1827348efd47831c13074245274d41b7cae8a557 directx_headers;https://github.com/microsoft/DirectX-Headers/archive/refs/tags/v1.613.1.zip;47653509a3371eabb156360f42faf582f314bf2e cudnn_frontend;https://github.com/NVIDIA/cudnn-frontend/archive/refs/tags/v1.7.0.zip;d0753d8d5b39947ca0729d7773cb84653a129eb1 -dawn;https://github.com/google/dawn/archive/40a9fa79f76e6c76cca9e2fa69ea07f202f1d2e6.zip;e224563d5ab4a8e53a517b06f721242533bce722 -kleidiai;https://gitlab.arm.com/kleidi/kleidiai/-/archive/d15722976120710080ca098fe8ddabf4556cb40f/kleidiai-d15722976120710080ca098fe8ddabf4556cb40f.zip;d6c840d00c3b05aedf06e957ddaece1013d1f40b +dawn;https://github.com/google/dawn/archive/4cb1f9be152a4fa6bb695c08cd707ab078a1e2fb.zip;de39336b7715f53c14eec61072293b85cc73b691 +kleidiai;https://github.com/ARM-software/kleidiai/archive/refs/tags/v1.4.0.tar.gz;22d3b57b54a61c194ab256ff11b0353a3b220244 diff --git a/cmake/external/eigen.cmake b/cmake/external/eigen.cmake index f8856069733a2..9b5ca601df8d4 100644 --- a/cmake/external/eigen.cmake +++ b/cmake/external/eigen.cmake @@ -2,11 +2,12 @@ set(EIGEN_BUILD_DOC OFF CACHE BOOL "" FORCE) set(EIGEN_BUILD_BLAS OFF CACHE BOOL "" FORCE) set(EIGEN_BUILD_LAPACK OFF CACHE BOOL "" FORCE) set(EIGEN_BUILD_PKGCONFIG OFF CACHE BOOL "" FORCE) +set(EIGEN_BUILD_CMAKE_PACKAGE ON CACHE BOOL "" FORCE) onnxruntime_fetchcontent_declare( - eigen + Eigen3 URL ${DEP_URL_eigen} URL_HASH SHA1=${DEP_SHA1_eigen} EXCLUDE_FROM_ALL ) -onnxruntime_fetchcontent_makeavailable(eigen) +onnxruntime_fetchcontent_makeavailable(Eigen3) diff --git a/cmake/external/onnxruntime_external_deps.cmake b/cmake/external/onnxruntime_external_deps.cmake index ebf20ab21bbd2..552b8b5329fb0 100644 --- a/cmake/external/onnxruntime_external_deps.cmake +++ b/cmake/external/onnxruntime_external_deps.cmake @@ -107,23 +107,6 @@ if(onnxruntime_USE_MIMALLOC) FetchContent_MakeAvailable(mimalloc) endif() -#Protobuf depends on utf8_range -onnxruntime_fetchcontent_declare( - utf8_range - URL ${DEP_URL_utf8_range} - URL_HASH SHA1=${DEP_SHA1_utf8_range} - EXCLUDE_FROM_ALL - FIND_PACKAGE_ARGS NAMES utf8_range -) - -set(utf8_range_ENABLE_TESTS OFF CACHE BOOL "Build test suite" FORCE) -set(utf8_range_ENABLE_INSTALL OFF CACHE BOOL "Configure installation" FORCE) - -# The next line will generate an error message "fatal: not a git repository", but it is ok. It is from flatbuffers -onnxruntime_fetchcontent_makeavailable(utf8_range) -# protobuf's cmake/utf8_range.cmake has the following line -include_directories(${utf8_range_SOURCE_DIR}) - # Download a protoc binary from Internet if needed if(NOT ONNX_CUSTOM_PROTOC_EXECUTABLE AND NOT onnxruntime_USE_VCPKG) # This part of code is only for users' convenience. The code couldn't handle all cases. Users always can manually @@ -304,7 +287,7 @@ if(NOT TARGET Boost::mp11) EXCLUDE_FROM_ALL FIND_PACKAGE_ARGS NAMES Boost ) - onnxruntime_fetchcontent_makeavailable(mp11) + onnxruntime_fetchcontent_makeavailable(mp11) if(NOT TARGET Boost::mp11) add_library(Boost::mp11 ALIAS Boost::headers) endif() @@ -442,6 +425,9 @@ target_include_directories(safeint_interface INTERFACE ${safeint_SOURCE_DIR}) # Flatbuffers +if(onnxruntime_USE_VCPKG) + find_package(flatbuffers REQUIRED) +else() # We do not need to build flatc for iOS or Android Cross Compile if (CMAKE_SYSTEM_NAME STREQUAL "iOS" OR CMAKE_SYSTEM_NAME STREQUAL "Android" OR CMAKE_SYSTEM_NAME STREQUAL "Emscripten") set(FLATBUFFERS_BUILD_FLATC OFF CACHE BOOL "FLATBUFFERS_BUILD_FLATC" FORCE) @@ -492,6 +478,7 @@ namespace std { using ::getenv; } endif() endif() endif() +endif() # ONNX if (NOT onnxruntime_USE_FULL_PROTOBUF) @@ -636,9 +623,7 @@ if (onnxruntime_USE_WEBGPU) set(DAWN_ENABLE_NULL OFF CACHE BOOL "" FORCE) set(DAWN_FETCH_DEPENDENCIES ON CACHE BOOL "" FORCE) set(DAWN_BUILD_TESTS OFF CACHE BOOL "" FORCE) - if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") - set(DAWN_EMSCRIPTEN_TOOLCHAIN "${REPO_ROOT}/cmake/external/emsdk/upstream/emscripten" CACHE STRING "" FORCE) - else() + if (NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") if (onnxruntime_BUILD_DAWN_MONOLITHIC_LIBRARY) set(DAWN_BUILD_MONOLITHIC_LIBRARY ON CACHE BOOL "" FORCE) set(DAWN_ENABLE_INSTALL ON CACHE BOOL "" FORCE) @@ -672,17 +657,10 @@ if (onnxruntime_USE_WEBGPU) # disable things we don't use set(DAWN_DXC_ENABLE_ASSERTS_IN_NDEBUG OFF) - set(DAWN_ENABLE_DESKTOP_GL OFF CACHE BOOL "" FORCE) - set(DAWN_ENABLE_OPENGLES OFF CACHE BOOL "" FORCE) - set(DAWN_SUPPORTS_GLFW_FOR_WINDOWING OFF CACHE BOOL "" FORCE) - set(DAWN_USE_GLFW OFF CACHE BOOL "" FORCE) - set(DAWN_USE_WINDOWS_UI OFF CACHE BOOL "" FORCE) set(DAWN_USE_X11 OFF CACHE BOOL "" FORCE) set(TINT_BUILD_TESTS OFF CACHE BOOL "" FORCE) set(TINT_BUILD_CMD_TOOLS OFF CACHE BOOL "" FORCE) - set(TINT_BUILD_GLSL_WRITER OFF CACHE BOOL "" FORCE) - set(TINT_BUILD_GLSL_VALIDATOR OFF CACHE BOOL "" FORCE) set(TINT_BUILD_IR_BINARY OFF CACHE BOOL "" FORCE) set(TINT_BUILD_SPV_READER OFF CACHE BOOL "" FORCE) # don't need. disabling is a large binary size saving set(TINT_BUILD_WGSL_WRITER ON CACHE BOOL "" FORCE) # needed to create cache key. runtime error if not enabled. @@ -732,7 +710,16 @@ if (onnxruntime_USE_WEBGPU) # # if we need to apply patches in the future, we can uncomment the following line. # # The dawn.patch contains the following changes: - # - https://dawn-review.googlesource.com/c/dawn/+/225514 + # + # - (private) Allow WGPUBufferImpl class to destroy the buffer in the destructor + # In native implementation, wgpuBufferRelease will trigger the buffer destroy (if refcount decreased to 0). But + # in emwgpu implementation, the buffer destroy won't happen. This change adds a destructor to the buffer class + # to destroy the buffer when the refcount is 0 for non-external buffers. + # + # - (private) Remove hard-coded CMAKE_OSX_DEPLOYMENT_TARGET in Dawn's CMake files + # https://github.com/microsoft/onnxruntime/pull/23729 + # + # PATCH_COMMAND ${Patch_EXECUTABLE} --binary --ignore-whitespace -p1 < ${PROJECT_SOURCE_DIR}/patches/dawn/dawn.patch EXCLUDE_FROM_ALL ) diff --git a/cmake/external/xnnpack.cmake b/cmake/external/xnnpack.cmake index 02ef9a198a803..d0ab770053be1 100644 --- a/cmake/external/xnnpack.cmake +++ b/cmake/external/xnnpack.cmake @@ -143,7 +143,12 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten") list(APPEND wasm_srcs ${XNNPACK_DIR}/src/amalgam/gen/scalar.c) list(APPEND wasm_srcs ${XNNPACK_DIR}/src/amalgam/gen/wasm.c) - if(onnxruntime_ENABLE_WEBASSEMBLY_SIMD) + if(onnxruntime_ENABLE_WEBASSEMBLY_RELAXED_SIMD) + list(APPEND wasm_srcs ${XNNPACK_DIR}/src/amalgam/gen/wasmsimd.c) + list(APPEND wasm_srcs ${XNNPACK_DIR}/src/amalgam/gen/wasmrelaxedsimd.c) + target_compile_options(XNNPACK PRIVATE "-msimd128") + target_compile_options(XNNPACK PRIVATE "-mrelaxed-simd") + elseif(onnxruntime_ENABLE_WEBASSEMBLY_SIMD) list(APPEND wasm_srcs ${XNNPACK_DIR}/src/amalgam/gen/wasmsimd.c) target_compile_options(XNNPACK PRIVATE "-msimd128") endif() diff --git a/cmake/nuget_helpers.cmake b/cmake/nuget_helpers.cmake index 22143ac422e9f..b066d1e9fb50e 100644 --- a/cmake/nuget_helpers.cmake +++ b/cmake/nuget_helpers.cmake @@ -1,7 +1,7 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.5) # Determines the version of a native nuget package from the root packages.config. # diff --git a/cmake/onnxruntime_common.cmake b/cmake/onnxruntime_common.cmake index e599e4f04ad91..3c526cd61418a 100644 --- a/cmake/onnxruntime_common.cmake +++ b/cmake/onnxruntime_common.cmake @@ -67,13 +67,13 @@ if(onnxruntime_target_platform STREQUAL "ARM64EC") link_directories("$ENV{VCINSTALLDIR}/Tools/MSVC/$ENV{VCToolsVersion}/lib/ARM64EC") link_directories("$ENV{VCINSTALLDIR}/Tools/MSVC/$ENV{VCToolsVersion}/ATLMFC/lib/ARM64EC") link_libraries(softintrin.lib) - add_compile_options("/bigobj") + add_compile_options("$<$>:/bigobj>") endif() endif() if(onnxruntime_target_platform STREQUAL "ARM64") if (MSVC) - add_compile_options("/bigobj") + add_compile_options("$<$>:/bigobj>") endif() endif() diff --git a/cmake/onnxruntime_mlas.cmake b/cmake/onnxruntime_mlas.cmake index 15864a0198161..8decca10937ba 100644 --- a/cmake/onnxruntime_mlas.cmake +++ b/cmake/onnxruntime_mlas.cmake @@ -27,6 +27,8 @@ onnxruntime_add_static_library(onnxruntime_mlas ${MLAS_SRC_DIR}/activate.cpp ${MLAS_SRC_DIR}/logistic.cpp ${MLAS_SRC_DIR}/tanh.cpp + ${MLAS_SRC_DIR}/eltwise.h + ${MLAS_SRC_DIR}/eltwise.cpp ${MLAS_SRC_DIR}/erf.cpp ${MLAS_SRC_DIR}/compute.cpp ${MLAS_SRC_DIR}/quantize.cpp @@ -101,6 +103,9 @@ function(setup_mlas_source_for_windows) ${MLAS_SRC_DIR}/softmax_kernel_neon.h ${MLAS_SRC_DIR}/softmax_kernel_neon.cpp ${MLAS_SRC_DIR}/softmax_kernel_neon_fp16.cpp + ${MLAS_SRC_DIR}/eltwise_kernel_neon.h + ${MLAS_SRC_DIR}/eltwise_kernel_neon.cpp + ${MLAS_SRC_DIR}/eltwise_kernel_neon_fp16.cpp ) set(mlas_platform_preprocess_srcs @@ -123,6 +128,10 @@ function(setup_mlas_source_for_windows) ${MLAS_SRC_DIR}/arm64/SymQgemmS8KernelSDot.asm ${MLAS_SRC_DIR}/arm64/SymQgemmS8KernelSDotLd64.asm ) + + if (onnxruntime_USE_KLEIDIAI) + setup_kleidiai() + endif() else() target_sources(onnxruntime_mlas PRIVATE ${MLAS_SRC_DIR}/qgemm_kernel_neon.cpp @@ -183,7 +192,7 @@ function(setup_mlas_source_for_windows) ${mlas_platform_srcs_avx2} ${MLAS_SRC_DIR}/rotary_embedding_kernel_avx2.h ${MLAS_SRC_DIR}/rotary_embedding_kernel_avx2.cpp - ${MLAS_SRC_DIR}/rotary_embedding_kernel_avx2_fp32.cpp + ${MLAS_SRC_DIR}/rotary_embedding_kernel_avx2.cpp ${MLAS_SRC_DIR}/qgemm_kernel_amx.cpp ${MLAS_SRC_DIR}/qgemm_kernel_avx2.cpp ${MLAS_SRC_DIR}/qgemm_kernel_sse.cpp @@ -251,6 +260,24 @@ function(setup_mlas_source_for_windows) endif() endfunction() +function(setup_kleidiai) + target_compile_definitions(onnxruntime_mlas PRIVATE USE_KLEIDIAI) + + # Disable the KleidiAI tests + set(KLEIDIAI_BUILD_TESTS OFF) + + # Fetch KleidiAI sources: + if (NOT TARGET kleidiai) + onnxruntime_fetchcontent_declare(kleidiai URL ${DEP_URL_kleidiai} URL_HASH SHA1=${DEP_SHA1_kleidiai} EXCLUDE_FROM_ALL) + endif() + onnxruntime_fetchcontent_makeavailable(kleidiai) + + target_sources(onnxruntime_mlas PRIVATE + ${MLAS_SRC_DIR}/kai_ukernel_interface.cpp + ) + target_link_libraries(onnxruntime_mlas PRIVATE kleidiai) +endfunction() + if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") if (onnxruntime_ENABLE_WEBASSEMBLY_SIMD) file(GLOB_RECURSE mlas_platform_srcs @@ -260,6 +287,12 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") ${mlas_platform_srcs} ${MLAS_SRC_DIR}/qgemm_kernel_wasmsimd.cpp ) + if (onnxruntime_ENABLE_WEBASSEMBLY_RELAXED_SIMD) + set(mlas_platform_srcs + ${mlas_platform_srcs} + ${MLAS_SRC_DIR}/qgemm_kernel_wasmrelaxedsimd.cpp + ) + endif() else() file(GLOB_RECURSE mlas_platform_srcs "${MLAS_SRC_DIR}/scalar/*.cpp" @@ -387,7 +420,12 @@ else() ${MLAS_SRC_DIR}/hgemm_kernel_neon.cpp ${MLAS_SRC_DIR}/softmax_kernel_neon.h ${MLAS_SRC_DIR}/softmax_kernel_neon.cpp + ${MLAS_SRC_DIR}/eltwise_kernel_neon.h + ${MLAS_SRC_DIR}/eltwise_kernel_neon.cpp ) + if (onnxruntime_USE_KLEIDIAI) + setup_kleidiai() + endif() set_source_files_properties(${MLAS_SRC_DIR}/sqnbitgemm_kernel_neon_int8.cpp PROPERTIES COMPILE_FLAGS " -march=armv8.2-a+dotprod") if (NOT APPLE) @@ -409,6 +447,7 @@ else() ${MLAS_SRC_DIR}/rotary_embedding_kernel_neon_fp16.cpp ${MLAS_SRC_DIR}/halfgemm_kernel_neon_fp16.cpp ${MLAS_SRC_DIR}/softmax_kernel_neon_fp16.cpp + ${MLAS_SRC_DIR}/eltwise_kernel_neon_fp16.cpp ) set_source_files_properties(${MLAS_SRC_DIR}/aarch64/HalfGemmKernelNeon.S PROPERTIES COMPILE_FLAGS " -march=armv8.2-a+fp16 ") set_source_files_properties(${MLAS_SRC_DIR}/aarch64/QgemmS8S8KernelSmmla.S PROPERTIES COMPILE_FLAGS " -march=armv8.2-a+i8mm ") @@ -423,6 +462,7 @@ else() set_source_files_properties(${MLAS_SRC_DIR}/rotary_embedding_kernel_neon_fp16.cpp PROPERTIES COMPILE_FLAGS " -march=armv8.2-a+fp16 ") set_source_files_properties(${MLAS_SRC_DIR}/halfgemm_kernel_neon_fp16.cpp PROPERTIES COMPILE_FLAGS " -march=armv8.2-a+fp16 ") set_source_files_properties(${MLAS_SRC_DIR}/softmax_kernel_neon_fp16.cpp PROPERTIES COMPILE_FLAGS " -march=armv8.2-a+fp16 ") + set_source_files_properties(${MLAS_SRC_DIR}/eltwise_kernel_neon_fp16.cpp PROPERTIES COMPILE_FLAGS " -march=armv8.2-a+fp16 ") endif() if(ONNXRUNTIME_MLAS_MULTI_ARCH) @@ -600,7 +640,7 @@ else() ${MLAS_SRC_DIR}/sqnbitgemm_kernel_avx2.cpp ${MLAS_SRC_DIR}/rotary_embedding_kernel_avx2.h ${MLAS_SRC_DIR}/rotary_embedding_kernel_avx2.cpp - ${MLAS_SRC_DIR}/rotary_embedding_kernel_avx2_fp32.cpp + ${MLAS_SRC_DIR}/rotary_embedding_kernel_avx2.cpp ) if(CMAKE_CXX_COMPILER_VERSION GREATER_EQUAL 13.1 AND NOT(APPLE)) set(mlas_platform_srcs_avx2 diff --git a/cmake/onnxruntime_optimizer.cmake b/cmake/onnxruntime_optimizer.cmake index 9d680cd04af10..173c872d4cc06 100644 --- a/cmake/onnxruntime_optimizer.cmake +++ b/cmake/onnxruntime_optimizer.cmake @@ -9,6 +9,7 @@ if (onnxruntime_MINIMAL_BUILD) list(APPEND onnxruntime_optimizer_src_patterns "${ONNXRUNTIME_INCLUDE_DIR}/core/optimizer/graph_transformer.h" "${ONNXRUNTIME_ROOT}/core/optimizer/graph_transformer.cc" + "${ONNXRUNTIME_ROOT}/core/optimizer/graph_optimizer_registry.cc" ) if (onnxruntime_EXTENDED_MINIMAL_BUILD) diff --git a/cmake/onnxruntime_providers_cpu.cmake b/cmake/onnxruntime_providers_cpu.cmake index beff30d193b94..3a5131947b917 100644 --- a/cmake/onnxruntime_providers_cpu.cmake +++ b/cmake/onnxruntime_providers_cpu.cmake @@ -217,7 +217,7 @@ set_target_properties(onnxruntime_providers PROPERTIES LINKER_LANGUAGE CXX) set_target_properties(onnxruntime_providers PROPERTIES FOLDER "ONNXRuntime") if (NOT onnxruntime_MINIMAL_BUILD AND NOT onnxruntime_EXTENDED_MINIMAL_BUILD - AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin|iOS|visionOS" + AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin|iOS|visionOS|tvOS" AND NOT CMAKE_SYSTEM_NAME STREQUAL "Android" AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") file(GLOB onnxruntime_providers_shared_cc_srcs CONFIGURE_DEPENDS diff --git a/cmake/onnxruntime_providers_migraphx.cmake b/cmake/onnxruntime_providers_migraphx.cmake index 685e77bc483bd..495ff093326ad 100644 --- a/cmake/onnxruntime_providers_migraphx.cmake +++ b/cmake/onnxruntime_providers_migraphx.cmake @@ -21,8 +21,10 @@ # Add search paths for default rocm installation list(APPEND CMAKE_PREFIX_PATH /opt/rocm/hcc /opt/rocm/hip /opt/rocm $ENV{HIP_PATH}) - # Suppress the warning about the small capitals of the package name - Enable when support to CMake 3.27.0 is used - # cmake_policy(SET CMP0144 NEW) + if(POLICY CMP0144) + # Suppress the warning about the small capitals of the package name + cmake_policy(SET CMP0144 NEW) + endif() if(WIN32 AND NOT HIP_PLATFORM) set(HIP_PLATFORM "amd") diff --git a/cmake/onnxruntime_providers_tensorrt.cmake b/cmake/onnxruntime_providers_tensorrt.cmake index 7fa5ba5f7f8d4..1f7700fa7bc36 100644 --- a/cmake/onnxruntime_providers_tensorrt.cmake +++ b/cmake/onnxruntime_providers_tensorrt.cmake @@ -28,18 +28,10 @@ endif() set(CXX_VERSION_DEFINED TRUE) - # There is an issue when running "Debug build" TRT EP with "Release build" TRT builtin parser on Windows. - # We enforce following workaround for now until the real fix. - if (WIN32 AND CMAKE_BUILD_TYPE STREQUAL "Debug") - set(onnxruntime_USE_TENSORRT_BUILTIN_PARSER OFF) - MESSAGE(STATUS "[Note] There is an issue when running \"Debug build\" TRT EP with \"Release build\" TRT built-in parser on Windows. This build will use tensorrt oss parser instead.") - endif() - find_path(TENSORRT_INCLUDE_DIR NvInfer.h HINTS ${TENSORRT_ROOT} PATH_SUFFIXES include) - file(READ ${TENSORRT_INCLUDE_DIR}/NvInferVersion.h NVINFER_VER_CONTENT) string(REGEX MATCH "define NV_TENSORRT_MAJOR * +([0-9]+)" NV_TENSORRT_MAJOR "${NVINFER_VER_CONTENT}") string(REGEX REPLACE "define NV_TENSORRT_MAJOR * +([0-9]+)" "\\1" NV_TENSORRT_MAJOR "${NV_TENSORRT_MAJOR}") diff --git a/cmake/onnxruntime_providers_vitisai.cmake b/cmake/onnxruntime_providers_vitisai.cmake index 561a323533f48..e40521e564ab8 100644 --- a/cmake/onnxruntime_providers_vitisai.cmake +++ b/cmake/onnxruntime_providers_vitisai.cmake @@ -20,7 +20,7 @@ ) source_group(TREE ${ONNXRUNTIME_ROOT}/core FILES ${onnxruntime_providers_vitisai_cc_srcs}) onnxruntime_add_shared_library(onnxruntime_providers_vitisai ${onnxruntime_providers_vitisai_cc_srcs}) - onnxruntime_add_include_to_target(onnxruntime_providers_vitisai ${ONNXRUNTIME_PROVIDERS_SHARED} ${GSL_TARGET} safeint_interface flatbuffers::flatbuffers) + onnxruntime_add_include_to_target(onnxruntime_providers_vitisai ${ONNXRUNTIME_PROVIDERS_SHARED} ${GSL_TARGET} safeint_interface flatbuffers::flatbuffers Boost::mp11) target_link_libraries(onnxruntime_providers_vitisai PRIVATE ${ONNXRUNTIME_PROVIDERS_SHARED}) if(MSVC) onnxruntime_add_include_to_target(onnxruntime_providers_vitisai dbghelp) diff --git a/cmake/onnxruntime_python.cmake b/cmake/onnxruntime_python.cmake index aee6d2ff7655c..ca65c02a40c3b 100644 --- a/cmake/onnxruntime_python.cmake +++ b/cmake/onnxruntime_python.cmake @@ -725,7 +725,7 @@ if (onnxruntime_ENABLE_EXTERNAL_CUSTOM_OP_SCHEMAS) endif() if (NOT onnxruntime_MINIMAL_BUILD AND NOT onnxruntime_EXTENDED_MINIMAL_BUILD - AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin|iOS|visionOS" + AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin|iOS|visionOS|tvOS" AND NOT CMAKE_SYSTEM_NAME STREQUAL "Android" AND NOT onnxruntime_USE_ROCM AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") @@ -1029,7 +1029,7 @@ if (onnxruntime_USE_QNN) add_custom_command( TARGET onnxruntime_pybind11_state POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy - $ + $ $/onnxruntime/capi/ ) if (EXISTS "${onnxruntime_QNN_HOME}/Qualcomm AI Hub Proprietary License.pdf") diff --git a/cmake/onnxruntime_session.cmake b/cmake/onnxruntime_session.cmake index 3d63285d50e72..2c2c59091fae5 100644 --- a/cmake/onnxruntime_session.cmake +++ b/cmake/onnxruntime_session.cmake @@ -22,6 +22,7 @@ endif() if (onnxruntime_MINIMAL_BUILD) set(onnxruntime_session_src_exclude "${ONNXRUNTIME_ROOT}/core/session/provider_bridge_ort.cc" + "${ONNXRUNTIME_ROOT}/core/session/model_builder_c_api.cc" ) list(REMOVE_ITEM onnxruntime_session_srcs ${onnxruntime_session_src_exclude}) diff --git a/cmake/onnxruntime_tvos.toolchain.cmake b/cmake/onnxruntime_tvos.toolchain.cmake new file mode 100644 index 0000000000000..5c992a1f465c6 --- /dev/null +++ b/cmake/onnxruntime_tvos.toolchain.cmake @@ -0,0 +1,12 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +set(CMAKE_SYSTEM_NAME tvOS) +set(CMAKE_SYSTEM_PROCESSOR arm64) + +if (NOT DEFINED CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM AND NOT DEFINED CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY) + set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED NO) +endif() + +SET(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_MODULES "YES") +SET(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "YES") diff --git a/cmake/onnxruntime_unittests.cmake b/cmake/onnxruntime_unittests.cmake index 0916aeb3dd92c..08807faa3e9b7 100644 --- a/cmake/onnxruntime_unittests.cmake +++ b/cmake/onnxruntime_unittests.cmake @@ -222,8 +222,11 @@ function(AddTest) else() set(TEST_NODE_FLAGS) + if (onnxruntime_ENABLE_WEBASSEMBLY_RELAXED_SIMD) + message(WARNING "Use system `node` to test Wasm relaxed SIMD. Please make sure to install node v21 or newer.") + set(NODE_EXECUTABLE node) # prefer Node from emsdk so the version is more deterministic - if (DEFINED ENV{EMSDK_NODE}) + elseif (DEFINED ENV{EMSDK_NODE}) set(NODE_EXECUTABLE $ENV{EMSDK_NODE}) else() message(WARNING "EMSDK_NODE environment variable was not set. Falling back to system `node`.") @@ -236,14 +239,14 @@ function(AddTest) ) endif() # Set test timeout to 3 hours. - set_tests_properties(${_UT_TARGET} PROPERTIES TIMEOUT 7200) + set_tests_properties(${_UT_TARGET} PROPERTIES TIMEOUT 10800) else() add_test(NAME ${_UT_TARGET} COMMAND ${_UT_TARGET} ${TEST_ARGS} WORKING_DIRECTORY $ ) # Set test timeout to 3 hours. - set_tests_properties(${_UT_TARGET} PROPERTIES TIMEOUT 7200) + set_tests_properties(${_UT_TARGET} PROPERTIES TIMEOUT 10800) endif() endif() endfunction(AddTest) @@ -503,6 +506,7 @@ set (onnxruntime_shared_lib_test_SRC if (NOT onnxruntime_MINIMAL_BUILD) list(APPEND onnxruntime_shared_lib_test_SRC ${ONNXRUNTIME_SHARED_LIB_TEST_SRC_DIR}/test_inference.cc) + list(APPEND onnxruntime_shared_lib_test_SRC ${ONNXRUNTIME_SHARED_LIB_TEST_SRC_DIR}/test_model_builder_api.cc) endif() if(onnxruntime_RUN_ONNX_TESTS) @@ -1288,31 +1292,34 @@ if (NOT onnxruntime_ENABLE_TRAINING_TORCH_INTEROP) if(onnxruntime_USE_QNN) #qnn ctx generator - set(onnxruntime_qnn_ctx_gen_src_dir ${TEST_SRC_DIR}/qnn_ctx_gen) - set(onnxruntime_qnn_ctx_gen_src_patterns - "${onnxruntime_qnn_ctx_gen_src_dir}/*.cc" - "${onnxruntime_qnn_ctx_gen_src_dir}/*.h") + set(ep_weight_sharing_ctx_gen_src_dir ${TEST_SRC_DIR}/ep_weight_sharing_ctx_gen) + set(ep_weight_sharing_ctx_gen_src_patterns + "${ep_weight_sharing_ctx_gen_src_dir}/*.cc" + "${ep_weight_sharing_ctx_gen_src_dir}/*.h") - file(GLOB onnxruntime_qnn_ctx_gen_src CONFIGURE_DEPENDS - ${onnxruntime_qnn_ctx_gen_src_patterns} + file(GLOB ep_weight_sharing_ctx_gen_src CONFIGURE_DEPENDS + ${ep_weight_sharing_ctx_gen_src_patterns} ) - onnxruntime_add_executable(onnxruntime_qnn_ctx_gen ${onnxruntime_qnn_ctx_gen_src}) - target_include_directories(onnxruntime_qnn_ctx_gen PRIVATE ${onnx_test_runner_src_dir} ${ONNXRUNTIME_ROOT} - ${onnxruntime_graph_header} ${onnxruntime_exec_src_dir} - ${CMAKE_CURRENT_BINARY_DIR}) + onnxruntime_add_executable(ep_weight_sharing_ctx_gen ${ep_weight_sharing_ctx_gen_src}) + target_include_directories(ep_weight_sharing_ctx_gen PRIVATE ${ONNXRUNTIME_ROOT} ${CMAKE_CURRENT_BINARY_DIR}) if (WIN32) - target_compile_options(onnxruntime_qnn_ctx_gen PRIVATE ${disabled_warnings}) + target_compile_options(ep_weight_sharing_ctx_gen PRIVATE ${disabled_warnings}) if (NOT DEFINED SYS_PATH_LIB) set(SYS_PATH_LIB shlwapi) endif() endif() - if(WIN32) - target_link_libraries(onnxruntime_qnn_ctx_gen PRIVATE debug dbghelp advapi32) + if (onnxruntime_BUILD_SHARED_LIB) + set(ep_weight_sharing_ctx_gen_libs onnxruntime_common onnxruntime ${onnxruntime_EXTERNAL_LIBRARIES} ${GETOPT_LIB_WIDE}) + target_link_libraries(ep_weight_sharing_ctx_gen PRIVATE ${ep_weight_sharing_ctx_gen_libs}) + if (WIN32) + target_link_libraries(ep_weight_sharing_ctx_gen PRIVATE debug dbghelp advapi32) + endif() + else() + target_link_libraries(ep_weight_sharing_ctx_gen PRIVATE onnxruntime_session ${onnxruntime_test_providers_libs} ${onnxruntime_EXTERNAL_LIBRARIES} ${GETOPT_LIB_WIDE}) endif() - target_link_libraries(onnxruntime_qnn_ctx_gen PRIVATE onnx_test_runner_common onnxruntime_test_utils onnxruntime_common onnxruntime_graph onnxruntime_session onnxruntime_providers onnxruntime_framework onnxruntime_util onnxruntime_mlas onnxruntime_optimizer onnxruntime_flatbuffers onnx_test_data_proto ${onnxruntime_test_providers_libs} ${onnxruntime_EXTERNAL_LIBRARIES} ${GETOPT_LIB_WIDE} ${SYS_PATH_LIB} ${CMAKE_DL_LIBS}) - set_target_properties(onnxruntime_qnn_ctx_gen PROPERTIES FOLDER "ONNXRuntimeTest") + set_target_properties(ep_weight_sharing_ctx_gen PROPERTIES FOLDER "ONNXRuntimeTest") endif() # shared lib @@ -1359,14 +1366,19 @@ if (NOT onnxruntime_ENABLE_TRAINING_TORCH_INTEROP) LIBS ${onnxruntime_shared_lib_test_LIBS} DEPENDS ${all_dependencies} ) + + target_include_directories(onnxruntime_shared_lib_test PRIVATE ${ONNXRUNTIME_ROOT}) + if (onnxruntime_USE_CUDA) target_include_directories(onnxruntime_shared_lib_test PRIVATE ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}) target_sources(onnxruntime_shared_lib_test PRIVATE ${ONNXRUNTIME_SHARED_LIB_TEST_SRC_DIR}/cuda_ops.cu) endif() + if (onnxruntime_USE_ROCM) target_include_directories(onnxruntime_shared_lib_test PRIVATE ${onnxruntime_ROCM_HOME}/include) target_compile_definitions(onnxruntime_shared_lib_test PRIVATE __HIP_PLATFORM_AMD__) endif() + if (CMAKE_SYSTEM_NAME STREQUAL "Android") target_sources(onnxruntime_shared_lib_test PRIVATE "${ONNXRUNTIME_ROOT}/core/platform/android/cxa_demangle.cc" @@ -1834,7 +1846,7 @@ endif() # limit to only test on windows first, due to a runtime path issue on linux if (NOT onnxruntime_MINIMAL_BUILD AND NOT onnxruntime_EXTENDED_MINIMAL_BUILD - AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin|iOS|visionOS" + AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin|iOS|visionOS|tvOS" AND NOT CMAKE_SYSTEM_NAME STREQUAL "Android" AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten" AND NOT onnxruntime_USE_ROCM) diff --git a/cmake/onnxruntime_webassembly.cmake b/cmake/onnxruntime_webassembly.cmake index 8106e46ccf580..bfb73e14ce7a4 100644 --- a/cmake/onnxruntime_webassembly.cmake +++ b/cmake/onnxruntime_webassembly.cmake @@ -211,10 +211,14 @@ else() target_link_libraries(onnxruntime_webassembly PRIVATE tensorboard) endif() + set(onnxruntime_webassembly_script_deps "${ONNXRUNTIME_ROOT}/wasm/pre.js") + + set(EXPORTED_FUNCTIONS "_malloc,_free") if (onnxruntime_USE_JSEP) - set(EXPORTED_FUNCTIONS "_malloc,_free,_JsepOutput,_JsepGetNodeName") - else() - set(EXPORTED_FUNCTIONS "_malloc,_free") + string(APPEND EXPORTED_FUNCTIONS ",_JsepOutput,_JsepGetNodeName") + endif() + if (onnxruntime_USE_WEBGPU) + string(APPEND EXPORTED_FUNCTIONS ",_wgpuBufferRelease,_wgpuCreateInstance") endif() if (onnxruntime_ENABLE_WEBASSEMBLY_MEMORY64) @@ -312,13 +316,15 @@ else() target_compile_options(noexcep_operators PRIVATE ${SMEMORY_FLAG} -Wno-experimental) endif() target_link_options(onnxruntime_webassembly PRIVATE - --post-js "${ONNXRUNTIME_ROOT}/wasm/js_post_js_64.js" + "SHELL:--post-js \"${ONNXRUNTIME_ROOT}/wasm/js_post_js_64.js\"" ) + list(APPEND onnxruntime_webassembly_script_deps "${ONNXRUNTIME_ROOT}/wasm/js_post_js_64.js") else () set(MAXIMUM_MEMORY "4294967296") target_link_options(onnxruntime_webassembly PRIVATE - --post-js "${ONNXRUNTIME_ROOT}/wasm/js_post_js.js" + "SHELL:--post-js \"${ONNXRUNTIME_ROOT}/wasm/js_post_js.js\"" ) + list(APPEND onnxruntime_webassembly_script_deps "${ONNXRUNTIME_ROOT}/wasm/js_post_js.js") endif () target_link_options(onnxruntime_webassembly PRIVATE @@ -372,7 +378,6 @@ jsepDownload:_pp_") "SHELL:-s SIGNATURE_CONVERSIONS='${SIGNATURE_CONVERSIONS}'" ) endif () - set_target_properties(onnxruntime_webassembly PROPERTIES LINK_DEPENDS ${ONNXRUNTIME_ROOT}/wasm/pre.js) if (onnxruntime_USE_JSEP) # NOTE: "-s ASYNCIFY=1" is required for JSEP to work with WebGPU @@ -382,10 +387,8 @@ jsepDownload:_pp_") target_compile_definitions(onnxruntime_webassembly PRIVATE USE_JSEP=1) target_link_options(onnxruntime_webassembly PRIVATE "SHELL:--pre-js \"${ONNXRUNTIME_ROOT}/wasm/pre-jsep.js\"" - "SHELL:-s ASYNCIFY=1" - "SHELL:-s ASYNCIFY_STACK_SIZE=65536" ) - set_target_properties(onnxruntime_webassembly PROPERTIES LINK_DEPENDS ${ONNXRUNTIME_ROOT}/wasm/pre-jsep.js) + list(APPEND onnxruntime_webassembly_script_deps "${ONNXRUNTIME_ROOT}/wasm/pre-jsep.js") if (onnxruntime_ENABLE_WEBASSEMBLY_MEMORY64) target_link_options(onnxruntime_webassembly PRIVATE @@ -397,6 +400,20 @@ jsepDownload:_pp_") if (onnxruntime_USE_WEBGPU) target_compile_definitions(onnxruntime_webassembly PRIVATE USE_WEBGPU=1) + target_link_options(onnxruntime_webassembly PRIVATE + "SHELL:--post-js \"${ONNXRUNTIME_ROOT}/wasm/post-webgpu.js\"" + ) + list(APPEND onnxruntime_webassembly_script_deps "${ONNXRUNTIME_ROOT}/wasm/post-webgpu.js") + endif() + + if (onnxruntime_USE_JSEP OR onnxruntime_USE_WEBGPU OR onnxruntime_USE_WEBNN) + # if any of the above is enabled, we need to use the asyncify library + target_link_options(onnxruntime_webassembly PRIVATE + "SHELL:--pre-js \"${ONNXRUNTIME_ROOT}/wasm/pre-async.js\"" + "SHELL:-s ASYNCIFY=1" + "SHELL:-s ASYNCIFY_STACK_SIZE=65536" + ) + list(APPEND onnxruntime_webassembly_script_deps "${ONNXRUNTIME_ROOT}/wasm/pre-async.js") endif() if (onnxruntime_EMSCRIPTEN_SETTINGS) @@ -458,6 +475,8 @@ jsepDownload:_pp_") ) endif() + set_target_properties(onnxruntime_webassembly PROPERTIES LINK_DEPENDS "${onnxruntime_webassembly_script_deps}") + set(target_name_list ort) if (onnxruntime_ENABLE_TRAINING_APIS) @@ -466,7 +485,9 @@ jsepDownload:_pp_") list(APPEND target_name_list "wasm") - if (onnxruntime_ENABLE_WEBASSEMBLY_SIMD) + if (onnxruntime_ENABLE_WEBASSEMBLY_RELAXED_SIMD) + list(APPEND target_name_list "relaxedsimd") + elseif (onnxruntime_ENABLE_WEBASSEMBLY_SIMD) list(APPEND target_name_list "simd") endif() diff --git a/cmake/patches/dawn/dawn.patch b/cmake/patches/dawn/dawn.patch index 2f85d5ab473b5..1ce9c75f750f1 100644 --- a/cmake/patches/dawn/dawn.patch +++ b/cmake/patches/dawn/dawn.patch @@ -11,26 +11,28 @@ index 50638e2456..efa42711e6 100644 - set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0" CACHE STRING "Minimum macOS version" FORCE) -endif () \ No newline at end of file -diff --git a/src/emdawnwebgpu/CMakeLists.txt b/src/emdawnwebgpu/CMakeLists.txt -index 6e8ae37593..633af91eef 100644 ---- a/src/emdawnwebgpu/CMakeLists.txt -+++ b/src/emdawnwebgpu/CMakeLists.txt -@@ -77,9 +77,17 @@ if (${DAWN_ENABLE_EMSCRIPTEN}) - "${arg_UNPARSED_ARGUMENTS}") - endif() - -+ # since Emscripten 4.0.3, file gen_struct_info.py is moved to outside of directory maint. -+ if (EXISTS "${DAWN_EMSCRIPTEN_TOOLCHAIN}/tools/gen_struct_info.py") -+ set(EM_GEN_STRUCT_INFO_SCRIPT "${DAWN_EMSCRIPTEN_TOOLCHAIN}/tools/gen_struct_info.py") -+ elseif (EXISTS "${DAWN_EMSCRIPTEN_TOOLCHAIN}/tools/maint/gen_struct_info.py") -+ set(EM_GEN_STRUCT_INFO_SCRIPT "${DAWN_EMSCRIPTEN_TOOLCHAIN}/tools/maint/gen_struct_info.py") -+ else() -+ message(FATAL_ERROR "Dawn: Failed to locate file gen_struct_info.py from Emscripten.") -+ endif() - set(ARGS - ${Python3_EXECUTABLE} -- "${DAWN_EMSCRIPTEN_TOOLCHAIN}/tools/maint/gen_struct_info.py" -+ "${EM_GEN_STRUCT_INFO_SCRIPT}" - -q - "${EM_BUILD_GEN_DIR}/struct_info_webgpu.json" - "-I=${EM_BUILD_GEN_DIR}/include" +diff --git a/third_party/emdawnwebgpu/webgpu.cpp b/third_party/emdawnwebgpu/webgpu.cpp +index 5bfac41dcc..71a153daaa 100644 +--- a/third_party/emdawnwebgpu/webgpu.cpp ++++ b/third_party/emdawnwebgpu/webgpu.cpp +@@ -692,6 +692,7 @@ struct WGPUBufferImpl final : public EventSource, + WGPUBufferImpl(const EventSource* source, bool mappedAtCreation); + // Injection constructor used when we already have a backing Buffer. + WGPUBufferImpl(const EventSource* source, WGPUBufferMapState mapState); ++ ~WGPUBufferImpl(); + + void Destroy(); + const void* GetConstMappedRange(size_t offset, size_t size); +@@ -1361,6 +1362,12 @@ WGPUBufferImpl::WGPUBufferImpl(const EventSource* source, + RefCountedWithExternalCount(kImportedFromJS), + mMapState(mapState) {} + ++WGPUBufferImpl::~WGPUBufferImpl() { ++ if (!IsImported()) { ++ Destroy(); ++ } ++} ++ + void WGPUBufferImpl::Destroy() { + emwgpuBufferDestroy(this); + AbortPendingMap("Buffer was destroyed before mapping was resolved."); diff --git a/cmake/winml_sdk_helpers.cmake b/cmake/winml_sdk_helpers.cmake index 9241fcd060caf..ca657311b7f14 100644 --- a/cmake/winml_sdk_helpers.cmake +++ b/cmake/winml_sdk_helpers.cmake @@ -1,7 +1,7 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.5) # utility function(convert_forward_slashes_to_back input output) diff --git a/csharp/sample/Microsoft.ML.OnnxRuntime.FasterRcnnSample/Microsoft.ML.OnnxRuntime.FasterRcnnSample.csproj b/csharp/sample/Microsoft.ML.OnnxRuntime.FasterRcnnSample/Microsoft.ML.OnnxRuntime.FasterRcnnSample.csproj index f00a08a1a3595..b1452a64934c2 100644 --- a/csharp/sample/Microsoft.ML.OnnxRuntime.FasterRcnnSample/Microsoft.ML.OnnxRuntime.FasterRcnnSample.csproj +++ b/csharp/sample/Microsoft.ML.OnnxRuntime.FasterRcnnSample/Microsoft.ML.OnnxRuntime.FasterRcnnSample.csproj @@ -8,7 +8,7 @@ - + diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/ManagedProjections.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/ManagedProjections.shared.cs index 13117f23e8ef9..8916f11919cfe 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/ManagedProjections.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/ManagedProjections.shared.cs @@ -25,7 +25,7 @@ internal class ManagedTypeProjection /// /// /// - /// OrtValye created accoding to the metadata + /// OrtValue created according to the metadata internal static OrtValue CreateProjection(NamedOnnxValue namedOnnxValue, NodeMetadata metadata) { OrtValue result; @@ -191,4 +191,3 @@ private static OrtValue CreateTensorProjection(NamedOnnxValue node, NodeMetadata } } } - diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/NativeMethods.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/NativeMethods.shared.cs index d628b065ceaa7..77c35aac65b92 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/NativeMethods.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/NativeMethods.shared.cs @@ -3,6 +3,7 @@ using System; using System.Runtime.InteropServices; +using static Microsoft.ML.OnnxRuntime.NativeMethods; namespace Microsoft.ML.OnnxRuntime { @@ -325,6 +326,16 @@ public struct OrtApi public IntPtr CreateLoraAdapterFromArray; public IntPtr ReleaseLoraAdapter; public IntPtr RunOptionsAddActiveLoraAdapter; + public IntPtr SetEpDynamicOptions; + public IntPtr ReleaseValueInfo; + public IntPtr ReleaseNode; + public IntPtr ReleaseGraph; + public IntPtr ReleaseModel; + public IntPtr GetValueInfoName; + public IntPtr GetValueInfoTypeInfo; + public IntPtr GetModelEditorApi; + public IntPtr CreateTensorWithDataAndDeleterAsOrtValue; + public IntPtr SessionOptionsSetLoadCancellationFlag; } internal static class NativeMethods @@ -404,6 +415,7 @@ static NativeMethods() OrtReleaseSessionOptions = (DOrtReleaseSessionOptions)Marshal.GetDelegateForFunctionPointer(api_.ReleaseSessionOptions, typeof(DOrtReleaseSessionOptions)); OrtCloneSessionOptions = (DOrtCloneSessionOptions)Marshal.GetDelegateForFunctionPointer(api_.CloneSessionOptions, typeof(DOrtCloneSessionOptions)); OrtSetSessionExecutionMode = (DOrtSetSessionExecutionMode)Marshal.GetDelegateForFunctionPointer(api_.SetSessionExecutionMode, typeof(DOrtSetSessionExecutionMode)); + OrtSessionOptionsSetLoadCancellationFlag = (DOrtSessionOptionsSetLoadCancellationFlag)Marshal.GetDelegateForFunctionPointer(api_.SessionOptionsSetLoadCancellationFlag, typeof(DOrtSessionOptionsSetLoadCancellationFlag)); OrtSetOptimizedModelFilePath = (DOrtSetOptimizedModelFilePath)Marshal.GetDelegateForFunctionPointer(api_.SetOptimizedModelFilePath, typeof(DOrtSetOptimizedModelFilePath)); OrtEnableProfiling = (DOrtEnableProfiling)Marshal.GetDelegateForFunctionPointer(api_.EnableProfiling, typeof(DOrtEnableProfiling)); OrtDisableProfiling = (DOrtDisableProfiling)Marshal.GetDelegateForFunctionPointer(api_.DisableProfiling, typeof(DOrtDisableProfiling)); @@ -847,7 +859,7 @@ internal class NativeLib /// Creates an instance of OrtSession with provided parameters /// /// Native OrtEnv instance - /// Byte array correspoonding to the model + /// Byte array corresponding to the model /// Size of the model in bytes /// Native SessionOptions instance /// Native OrtPrepackedWeightsContainer instance @@ -1025,6 +1037,12 @@ IntPtr[] outputValues /* An array of output value pointers. Array must be alloca ExecutionMode execution_mode); public static DOrtSetSessionExecutionMode OrtSetSessionExecutionMode; + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate IntPtr /*(OrtStatus*)*/ DOrtSessionOptionsSetLoadCancellationFlag(IntPtr /*(OrtSessionOptions*)*/ options, + bool value); + public static DOrtSessionOptionsSetLoadCancellationFlag OrtSessionOptionsSetLoadCancellationFlag; + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] public delegate IntPtr /*(OrtStatus*)*/ DOrtSetOptimizedModelFilePath(IntPtr /* OrtSessionOptions* */ options, byte[] optimizedModelFilepath); public static DOrtSetOptimizedModelFilePath OrtSetOptimizedModelFilePath; @@ -1258,7 +1276,7 @@ IntPtr[] outputValues /* An array of output value pointers. Array must be alloca /// /// Native SessionOptions instance /// Name of the initializer - /// Native OrtValue instnce + /// Native OrtValue instance [UnmanagedFunctionPointer(CallingConvention.Winapi)] public delegate IntPtr /*(OrtStatus*)*/ DOrtAddInitializer(IntPtr /*(OrtSessionOptions*)*/ options, byte[] /*(const char*)*/ name, diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/SessionOptions.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/SessionOptions.shared.cs index bd450451a1265..9b0f183f03681 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/SessionOptions.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/SessionOptions.shared.cs @@ -802,6 +802,16 @@ public ExecutionMode ExecutionMode } private ExecutionMode _executionMode = ExecutionMode.ORT_SEQUENTIAL; + /// + /// Sets the load cancellation flag for the session. Default is set to false. + /// Provides an opportunity for the user to cancel model loading. + /// + /// true to request cancellation, false to proceed + public void SetLoadCancellationFlag(bool value) + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtSessionOptionsSetLoadCancellationFlag(handle, value)); + } + #endregion #region Private Methods diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/Training/NativeTrainingMethods.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/Training/NativeTrainingMethods.shared.cs index b4067806c5f93..5dd5b3ac620ab 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/Training/NativeTrainingMethods.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/Training/NativeTrainingMethods.shared.cs @@ -76,7 +76,7 @@ static NativeTrainingMethods() DOrtGetApi OrtGetApi = (DOrtGetApi)Marshal.GetDelegateForFunctionPointer(NativeMethods.OrtGetApiBase().GetApi, typeof(DOrtGetApi)); #endif - const uint ORT_API_VERSION = 21; + const uint ORT_API_VERSION = 22; #if NETSTANDARD2_0 IntPtr ortApiPtr = OrtGetApi(ORT_API_VERSION); api_ = (OrtApi)Marshal.PtrToStructure(ortApiPtr, typeof(OrtApi)); diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/Microsoft.ML.OnnxRuntime.EndToEndTests.csproj b/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/Microsoft.ML.OnnxRuntime.EndToEndTests.csproj index 67addd2731744..4da9b5ffae3e4 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/Microsoft.ML.OnnxRuntime.EndToEndTests.csproj +++ b/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/Microsoft.ML.OnnxRuntime.EndToEndTests.csproj @@ -50,6 +50,7 @@ + diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.BrowserStack.Android/BrowserStackTest.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.BrowserStack.Android/BrowserStackTest.cs index 84377d65d1213..6ab341d75683f 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.BrowserStack.Android/BrowserStackTest.cs +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.BrowserStack.Android/BrowserStackTest.cs @@ -45,8 +45,8 @@ public void Dispose() { String failureMessage = TestContext.CurrentContext.Result.Message; String jsonToSendFailure = - String.Format("browserstack_executor: {\"action\": \"setSessionStatus\", \"arguments\": " + - "{\"status\":\"failed\", \"reason\": {0}}}", + String.Format("browserstack_executor: {{\"action\": \"setSessionStatus\", \"arguments\": " + + "{{\"status\":\"failed\", \"reason\": {0}}}}}", JsonConvert.ToString(failureMessage)); ((IJavaScriptExecutor)driver).ExecuteScript(jsonToSendFailure); diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.BrowserStack.Android/RunAllTest.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.BrowserStack.Android/RunAllTest.cs index 5db3dc9957d1c..b62c2f052455e 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.BrowserStack.Android/RunAllTest.cs +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.BrowserStack.Android/RunAllTest.cs @@ -89,7 +89,7 @@ public async Task ClickRunAllTest() await Task.Delay(500); } - var (numPassed, numFailed) = GetPassFailCount(); + (int numPassed, int numFailed) = GetPassFailCount(); if (numFailed == 0) { diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/AssertUtils.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/AssertUtils.cs new file mode 100644 index 0000000000000..7d689628ceab7 --- /dev/null +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/AssertUtils.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; + +namespace Microsoft.ML.OnnxRuntime.Tests +{ + internal static class AssertUtils + { + + /// + /// Check if the action throws the expected exception. If it doesn't, the method passes. If it does, check for + /// the exception type and the expected exception message. More detailed Assert method to be used for unit tests + /// written with XUnit. + /// + /// Type of exception expected to be thrown. + /// Action to be executed or tested. + /// Feedback message if an unexpected exception happens. + /// Expected exception message. If null, the exception message is not + // checked. + public static void IfThrowsCheckException(Action action, string feedbackMessage, string expectedExceptionMessage = null) where T : Exception + { + try + { + action(); + } + catch (T ex) + { + if (expectedExceptionMessage == null) + { + return; + } + else + { + Assert.True(ex.Message.Contains(expectedExceptionMessage), + $"{feedbackMessage}\nExpected exception message to contain '{expectedExceptionMessage}', but got '{ex.Message}'"); + } + } + catch (Exception ex) + { + Assert.Fail($"{feedbackMessage}\nExpected {typeof(T).Name} but got {ex.GetType().Name}. "); + } + } + + + /// + /// Check if the action throws the expected exception. If it doesn't, the method fails with the feedbackMessage. + /// If it does, check for the exception type and the expected exception message. More detailed Assert method to be + /// used for unit tests written with XUnit. + /// + /// Type of exception expected to be thrown. + /// Action to be executed or tested. It is expected that the action will throw. + /// Feedback message if an unexpected exception happens. + /// Expected exception message. If null, the exception message is not + // checked. + public static void AssertThrowsCheckException(Action action, string feedbackMessage, string expectedExceptionMessage = null) where T : Exception + { + try + { + action(); + Assert.Fail($"{feedbackMessage}\nExpected {typeof(T).Name} but no exception was thrown."); + } + catch (T ex) + { + if (expectedExceptionMessage == null) + { + return; + } + else + { + Assert.True(ex.Message.Contains(expectedExceptionMessage), + $"{feedbackMessage}\nExpected exception message to contain '{expectedExceptionMessage}', but got '{ex.Message}'"); + } + } + catch (Exception ex) + { + Assert.Fail($"{feedbackMessage}\nExpected {typeof(T).Name} but got {ex.GetType().Name}. "); + } + } + } +} diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/InferenceTest.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/InferenceTest.cs index 17738da515134..0a39d965979ca 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/InferenceTest.cs +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/InferenceTest.cs @@ -93,18 +93,35 @@ public void TestSessionOptions() opt.GraphOptimizationLevel = GraphOptimizationLevel.ORT_ENABLE_EXTENDED; Assert.Equal(GraphOptimizationLevel.ORT_ENABLE_EXTENDED, opt.GraphOptimizationLevel); - Assert.Throws(() => { opt.GraphOptimizationLevel = (GraphOptimizationLevel)10; }); + AssertUtils.AssertThrowsCheckException( + () => { opt.GraphOptimizationLevel = (GraphOptimizationLevel)10; }, + "Set an invalid Graph Optimization Level."); opt.AddSessionConfigEntry("key", "value"); - var ex = Assert.Throws(() => { opt.AddSessionConfigEntry("", "invalid key"); }); - Assert.Contains("[ErrorCode:InvalidArgument] Config key is empty", ex.Message); + AssertUtils.AssertThrowsCheckException( + () => { opt.AddSessionConfigEntry("", "invalid key"); }, + "Added an invalid config entry.", + "[ErrorCode:InvalidArgument] Config key is empty"); // SessionOptions.RegisterOrtExtensions can be manually tested by referencing the // Microsoft.ML.OnnxRuntime.Extensions nuget package. After that is done, this should not throw. - ex = Assert.Throws(() => { opt.RegisterOrtExtensions(); }); - Assert.Contains("Microsoft.ML.OnnxRuntime.Extensions NuGet package must be referenced", ex.Message); - + AssertUtils.AssertThrowsCheckException( + () => { opt.RegisterOrtExtensions(); }, + "RegisterOrtExtensions should throw if the Extensions package is not referenced", + "Microsoft.ML.OnnxRuntime.Extensions NuGet package must be referenced"); + + // The below tests what happens when various execution providers are added + // to the session options. + + // We can only check what EPs the package was built with for the + // Microsoft.ML.OnnxRuntime.Managed package because the managed package defines + // the C# preprocessor symbols (such as USE_CUDA) for the EPs that it was built with. + + // The Microsoft.ML.OnnxRuntime package will use the appropriate platform bindings + // (ie the native Android bindings) where the C# preprocessor symbols + // identifying the EPs included in the build may not be available, so we use + // IfThrowsCheckException instead of using ifdefs. #if USE_CUDA opt.AppendExecutionProvider_CUDA(0); #endif @@ -157,30 +174,25 @@ public void TestSessionOptions() #if USE_TENSORRT opt.AppendExecutionProvider_Tensorrt(0); #endif -#if USE_XNNPACK - opt.AppendExecutionProvider("XNNPACK"); -#else - ex = Assert.Throws(() => { opt.AppendExecutionProvider("XNNPACK"); }); - Assert.Contains("XNNPACK execution provider is not supported in this build", ex.Message); -#endif -#if USE_SNPE - opt.AppendExecutionProvider("SNPE"); -#else - ex = Assert.Throws(() => { opt.AppendExecutionProvider("SNPE"); }); - Assert.Contains("SNPE execution provider is not supported in this build", ex.Message); -#endif -#if USE_QNN - opt.AppendExecutionProvider("QNN"); -#else - ex = Assert.Throws(() => { opt.AppendExecutionProvider("QNN"); }); - Assert.Contains("QNN execution provider is not supported in this build", ex.Message); -#endif -#if USE_COREML - opt.AppendExecutionProvider("CoreML"); -#else - ex = Assert.Throws(() => { opt.AppendExecutionProvider("CoreML"); }); - Assert.Contains("CoreML execution provider is not supported in this build", ex.Message); -#endif + AssertUtils.IfThrowsCheckException( + () => { opt.AppendExecutionProvider("CoreML"); }, + "Appending CoreML EP should have succeeded or thrown an OnnRuntimeException with the expected message. ", + "CoreML execution provider is not supported in this build"); + + AssertUtils.IfThrowsCheckException( + () => { opt.AppendExecutionProvider("XNNPACK"); }, + "Appending XNNPACK EP should have succeeded or thrown an OnnRuntimeException with the expected message. ", + "XNNPACK execution provider is not supported in this build"); + + AssertUtils.IfThrowsCheckException( + () => { opt.AppendExecutionProvider("SNPE"); }, + "Appending SNPE EP should have succeeded or thrown an OnnRuntimeException with the expected message. ", + "SNPE execution provider is not supported in this build"); + + AssertUtils.IfThrowsCheckException( + () => { opt.AppendExecutionProvider("QNN"); }, + "Appending QNN EP should have succeeded or thrown an OnnRuntimeException with the expected message. ", + "QNN execution provider is not supported in this build"); opt.AppendExecutionProvider_CPU(1); } diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/TrainingTest.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/TrainingTest.cs index 9b72326201322..455b48ec81a5c 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/TrainingTest.cs +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/TrainingTest.cs @@ -26,16 +26,6 @@ public TrainingTest(ITestOutputHelper o) this.output = o; } -#if !__TRAINING_ENABLED_NATIVE_BUILD__ - [Fact(DisplayName = "TestLoadCheckpointThrows")] - public void TestLoadCheckpointThrows() - { - string path = Path.Combine(Directory.GetCurrentDirectory(), "checkpoint.ckpt"); - var ex = Assert.Throws(() => { var opt = CheckpointState.LoadCheckpoint(path); }); - Assert.Contains("Please install the Microsoft.ML.OnnxRuntime.Training NuGet package.", ex.Message); - } -#endif - #if __TRAINING_ENABLED_NATIVE_BUILD__ [Fact(DisplayName = "TestLoadCheckpoint")] public void TestLoadCheckpoint() diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp/InferenceTest.netcore.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp/InferenceTest.netcore.cs index 816511150a137..eab4a3d412898 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp/InferenceTest.netcore.cs +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp/InferenceTest.netcore.cs @@ -74,11 +74,9 @@ public void CanCreateAndDisposeSessionWithModelPath() #if NET8_0_OR_GREATER #pragma warning disable SYSLIB5001 // System.Numerics.Tensors is only in preview so we can continue receiving API feedback [Theory] - [InlineData(GraphOptimizationLevel.ORT_DISABLE_ALL, true)] - [InlineData(GraphOptimizationLevel.ORT_DISABLE_ALL, false)] - [InlineData(GraphOptimizationLevel.ORT_ENABLE_EXTENDED, true)] - [InlineData(GraphOptimizationLevel.ORT_ENABLE_EXTENDED, false)] - private void CanRunInferenceOnAModelDotnetTensors(GraphOptimizationLevel graphOptimizationLevel, bool enableParallelExecution) + [InlineData(GraphOptimizationLevel.ORT_DISABLE_ALL)] + [InlineData(GraphOptimizationLevel.ORT_ENABLE_EXTENDED)] + private void CanRunInferenceOnAModelDotnetTensors(GraphOptimizationLevel graphOptimizationLevel) { var model = TestDataLoader.LoadModelFromEmbeddedResource("squeezenet.onnx"); @@ -151,7 +149,7 @@ public void InferenceSessionDisposedDotnetTensors() using (var inputOrtValues = new DisposableListTest>(session.InputMetadata.Count)) using (var outputOrtValues = new DisposableListTest>(session.OutputMetadata.Count)) { - + foreach (var name in inputMeta.Keys) { Assert.Equal(typeof(float), inputMeta[name].ElementType); @@ -159,7 +157,7 @@ public void InferenceSessionDisposedDotnetTensors() var tensor = SystemNumericsTensors.Tensor.Create(inputData, inputMeta[name].Dimensions.Select(x => (nint) x).ToArray()); inputOrtValues.Add(new DisposableTestPair(name, OrtValue.CreateTensorValueFromSystemNumericsTensorObject(tensor))); } - + // Run inference with named inputs and outputs created with in Run() using (var results = session.Run(runOptions, inputOrtValues.Select(x => x.Key).ToList(), inputOrtValues.Select(x => x.Value).ToList(), new List(["softmaxout_1"]))) // results is an IDisposableReadOnlyCollection container { @@ -224,7 +222,7 @@ private void ThrowWrongOutputDimensionDotnetTensors() inputOrtValues.Add(new DisposableTestPair("data_0", OrtValue.CreateTensorValueFromSystemNumericsTensorObject(tensor))); outputOrtValues.Add(new DisposableTestPair("softmaxout_1", OrtValue.CreateTensorValueFromSystemNumericsTensorObject(outputTensor))); - + var ex = Assert.Throws(() => session.Run(runOptions, ["data_0"], [inputOrtValues[0].Value], ["softmaxout_1"], [outputOrtValues[0].Value])); } diff --git a/docs/ContribOperators.md b/docs/ContribOperators.md index 274531faaf717..0308b5c79c508 100644 --- a/docs/ContribOperators.md +++ b/docs/ContribOperators.md @@ -1191,17 +1191,17 @@ This version of the operator has been available since version 1 of the 'com.micr
present state for key with shape (batch_size, num_heads, total_sequence_length, head_size). If past_present_share_buffer is set, its shape is (batch_size, num_heads, max_sequence_length, head_size), while effective_seq_length = (past_sequence_length + kv_sequence_length).
present_value (optional) : T
present state for value with shape (batch_size, num_heads, total_sequence_length, head_size). If past_present_share_buffer is set, its shape is (batch_size, num_heads, max_sequence_length, head_size), while effective_seq_length = (past_sequence_length + kv_sequence_length).
-
qk (optional) : V
+
qk (optional) : QK
normalized Q * K, of shape (batch_size, num_heads, 1, total_sequence_length).
#### Type Constraints
-
V : tensor(float)
-
Constrain qk output types to float32 tensors.
T : tensor(float), tensor(float16)
Constrain input and output types to float tensors.
+
QK : tensor(float), tensor(float16)
+
Constrain QK output to float32 or float16 tensors, independent of input type or output type.
M : tensor(int32)
Constrain mask index to integer types
@@ -1625,7 +1625,7 @@ This version of the operator has been available since version 1 of the 'com.micr #### Type Constraints
-
T : tensor(int8), tensor(int16), tensor(int32), tensor(int64), tensor(uint8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(float16), tensor(float), tensor(double), tensor(bfloat16)
+
T : tensor(bool), tensor(int8), tensor(int16), tensor(int32), tensor(int64), tensor(uint8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(float16), tensor(float), tensor(double), tensor(bfloat16)
Constrain input and output types.
@@ -2039,10 +2039,11 @@ This version of the operator has been available since version 1 of the 'com.micr 1. Input `data` is a constant. It is quantized block-wise along attribute `quantize_axis` with block size specified by attribute `block_size`. `block_size must` be a power of 2 and not smaller than 16, like 16, 32, 64, 128, .. 2. Input `data`'s scale and zero point are specified by input `scales` and `zero_points`. `scales` and `zero_points` are also constants. - If `zero_points` is not provided, 0 is the zero point. + If `zero_points` is not provided, 0 is the zero point except when data is uint8 type then the default zero point is 8. 3. During the op execution, `data` and `indices` are first used to generate the quantized output. Then, `scales` and `zero_points` are used to dequantize the output. 4. The `output` and `scales` have the same type. The `data` and `zero_points` have the same type. + 5. For uint8 data, the `gather_axis` must be 0. #### Version @@ -2082,7 +2083,7 @@ This version of the operator has been available since version 1 of the 'com.micr #### Type Constraints
-
T1 : tensor(int4), tensor(uint4)
+
T1 : tensor(int4), tensor(uint4), tensor(uint8)
Constrain quantized types.
T2 : tensor(float), tensor(float16), tensor(bfloat16)
Constrain dequantized types.
@@ -2551,7 +2552,7 @@ This version of the operator has been available since version 1 of the 'com.micr
Softcap value for attention weights. Default value is 0.
-#### Inputs (7 - 9) +#### Inputs (7 - 11)
query : T
@@ -2572,6 +2573,10 @@ This version of the operator has been available since version 1 of the 'com.micr
2D tensor with shape (max_sequence_length, head_size / 2).
sin_cache (optional) : T
2D tensor with shape (max_sequence_length, head_size / 2).
+
position_ids (optional) : tensor(int64)
+
2D tensor with shape (batch_size, sequence_length). When processing the first prompt the kernel uses only the first element
+
attention_bias (optional) : T
+
additional add to QxK' with shape (batch_size or 1, num_heads or 1, sequence_length, total_sequence_length)
#### Outputs @@ -3199,7 +3204,7 @@ This version of the operator has been available since version 1 of the 'com.micr
Whether every token can only attend to previous tokens. Default value is 0.
-#### Inputs (1 - 8) +#### Inputs (1 - 10)
query : T
@@ -3215,20 +3220,26 @@ This version of the operator has been available since version 1 of the 'com.micr
attention_bias (optional) : T
bias added to QxK' with shape (batch_size or 1, num_heads or 1, sequence_length, total_sequence_length)
past_key (optional) : T
-
past state for self attention key with shape (batch_size, num_heads, past_sequence_length, head_size)
+
past state for key with shape (batch_size, num_heads, past_sequence_length, head_size) or (batch_size, num_heads, max_sequence_length, head_size) when buffer sharing is used
past_value (optional) : T
-
past state for self attention value with shape (batch_size, num_heads, past_sequence_length, head_size)
+
past state for value with shape (batch_size, num_heads, past_sequence_length, head_size) or (batch_size, num_heads, max_sequence_length, head_size) when buffer sharing is used
+
past_sequence_length (optional) : M
+
The past_sequence_length buffer sharing is used with
+
cache_indirection (optional) : M
+
A buffer of shape [batch_size, beam_width, max_sequence_length] where an [i, j, k] entry specifieswhich beam the 'k' th token came from for the 'j' th beam for batch 'i' in the current iteration
-#### Outputs (1 - 3) +#### Outputs (1 - 4)
output : T
3D output tensor with shape (batch_size, sequence_length, v_hidden_size)
present_key (optional) : T
-
present state for cross attention key with shape (batch_size, num_heads, kv_sequence_length, head_size)or present state for self attention key with shape (batch_size, num_heads, total_sequence_length, head_size)
+
present state for key with shape (batch_size, num_heads, total_sequence_length, head_size) or (batch_size, num_heads, max_sequence_length, head_size) when buffer sharing is used
present_value (optional) : T
-
present state for cross attention value with shape (batch_size, num_heads, kv_sequence_length, head_size)or present state for self attention value with shape (batch_size, num_heads, total_sequence_length, head_size)
+
present state for value with shape (batch_size, num_heads, total_sequence_length, head_size) or (batch_size, num_heads, max_sequence_length, head_size) when buffer sharing is used
+
qk (optional) : QK
+
normalized Q * K, of shape (batch_size, num_heads, sequence_length, total_sequence_length).
#### Type Constraints @@ -3236,6 +3247,8 @@ This version of the operator has been available since version 1 of the 'com.micr
T : tensor(float), tensor(float16)
Constrain input and output to float tensors.
+
QK : tensor(float), tensor(float16)
+
Constrain QK output to float32 or float16 tensors, independent of input type or output type.
M : tensor(int32)
Constrain mask to integer types
diff --git a/docs/OperatorKernels.md b/docs/OperatorKernels.md index 84b9c7c9fc174..a20333e2340c4 100644 --- a/docs/OperatorKernels.md +++ b/docs/OperatorKernels.md @@ -504,7 +504,7 @@ Do not modify directly.* |CDist|*in* A:**T**
*in* B:**T**
*out* C:**T**|1+|**T** = tensor(double), tensor(float)| |ConvTransposeWithDynamicPads|*in* X:**T**
*in* W:**T**
*in* Pads:**tensor(int64)**
*in* B:**T**
*out* Y:**T**|1+|**T** = tensor(float)| |CropAndResize|*in* X:**T1**
*in* rois:**T1**
*in* batch_indices:**T2**
*in* crop_size:**T2**
*out* Y:**T1**|1+|**T1** = tensor(float)
**T2** = tensor(int32)| -|DecoderMaskedMultiHeadAttention|*in* query:**T**
*in* key:**T**
*in* value:**T**
*in* mask_index:**M**
*in* attention_bias:**T**
*in* past_key:**T**
*in* past_value:**T**
*in* past_sequence_length:**M**
*in* beam_width:**M**
*in* cache_indirection:**M**
*in* bias:**T**
*out* output:**T**
*out* present_key:**T**
*out* present_value:**T**
*out* qk:**V**|1+|**T** = tensor(float)| +|DecoderMaskedMultiHeadAttention|*in* query:**T**
*in* key:**T**
*in* value:**T**
*in* mask_index:**M**
*in* attention_bias:**T**
*in* past_key:**T**
*in* past_value:**T**
*in* past_sequence_length:**M**
*in* beam_width:**M**
*in* cache_indirection:**M**
*in* bias:**T**
*out* output:**T**
*out* present_key:**T**
*out* present_value:**T**
*out* qk:**QK**|1+|**T** = tensor(float)| |DequantizeLinear|*in* x:**T1**
*in* x_scale:**T2**
*in* x_zero_point:**T1**
*out* y:**T2**|1+|**T1** = tensor(int16), tensor(int32), tensor(int4), tensor(int8), tensor(uint16), tensor(uint4), tensor(uint8)
**T2** = tensor(float)| |DynamicQuantizeLSTM|*in* X:**T**
*in* W:**T2**
*in* R:**T2**
*in* B:**T**
*in* sequence_lens:**T1**
*in* initial_h:**T**
*in* initial_c:**T**
*in* P:**T**
*in* W_scale:**T**
*in* W_zero_point:**T2**
*in* R_scale:**T**
*in* R_zero_point:**T2**
*out* Y:**T**
*out* Y_h:**T**
*out* Y_c:**T**|1+|**T** = tensor(float)
**T1** = tensor(int32)
**T2** = tensor(int8), tensor(uint8)| |DynamicQuantizeMatMul|*in* A:**T1**
*in* B:**T2**
*in* b_scale:**T1**
*in* b_zero_point:**T2**
*in* bias:**T1**
*out* Y:**T1**|1+|**T1** = tensor(float)
**T2** = tensor(int8), tensor(uint8)| @@ -515,12 +515,12 @@ Do not modify directly.* |FusedConv|*in* X:**T**
*in* W:**T**
*in* B:**T**
*in* Z:**T**
*out* Y:**T**|1+|**T** = tensor(float)| |FusedGemm|*in* A:**T**
*in* B:**T**
*in* C:**T**
*out* Y:**T**|1+|**T** = tensor(float)| |FusedMatMul|*in* A:**T**
*in* B:**T**
*out* Y:**T**|1+|**T** = tensor(float)| -|GatherBlockQuantized|*in* data:**T1**
*in* indices:**Tind**
*in* scales:**T2**
*in* zero_points:**T1**
*out* output:**T2**|1+|**T1** = tensor(int4), tensor(uint4)
**T2** = tensor(float), tensor(float16)
**Tind** = tensor(int32), tensor(int64)| +|GatherBlockQuantized|*in* data:**T1**
*in* indices:**Tind**
*in* scales:**T2**
*in* zero_points:**T1**
*out* output:**T2**|1+|**T1** = tensor(int4), tensor(uint4), tensor(uint8)
**T2** = tensor(float), tensor(float16)
**Tind** = tensor(int32), tensor(int64)| |GatherND|*in* data:**T**
*in* indices:**Tind**
*out* output:**T**|1+|**T** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**Tind** = tensor(int32), tensor(int64)| |Gelu|*in* X:**T**
*out* Y:**T**|1+|**T** = tensor(float)| |GreedySearch|*in* input_ids:**I**
*in* max_length:**I**
*in* min_length:**I**
*in* repetition_penalty:**T**
*in* vocab_mask:**I**
*in* prefix_vocab_mask:**I**
*in* attention_mask:**I**
*out* sequences:**I**|1+|**T** = tensor(float)| |GridSample|*in* X:**T1**
*in* Grid:**T1**
*out* Y:**T2**|1+|**T1** = tensor(float)
**T2** = tensor(float)| -|GroupQueryAttention|*in* query:**T**
*in* key:**T**
*in* value:**T**
*in* past_key:**T**
*in* past_value:**T**
*in* seqlens_k:**M**
*in* total_sequence_length:**M**
*in* cos_cache:**T**
*in* sin_cache:**T**
*out* output:**T**
*out* present_key:**T**
*out* present_value:**T**|1+|**M** = tensor(int32)
**T** = tensor(float), tensor(float16)| +|GroupQueryAttention|*in* query:**T**
*in* key:**T**
*in* value:**T**
*in* past_key:**T**
*in* past_value:**T**
*in* seqlens_k:**M**
*in* total_sequence_length:**M**
*in* cos_cache:**T**
*in* sin_cache:**T**
*in* position_ids:**tensor(int64)**
*in* attention_bias:**T**
*out* output:**T**
*out* present_key:**T**
*out* present_value:**T**|1+|**M** = tensor(int32)
**T** = tensor(float), tensor(float16)| |Inverse|*in* X:**T**
*out* Y:**T**|1+|**T** = tensor(double), tensor(float), tensor(float16)| |MatMulBnb4|*in* A:**T1**
*in* B:**T2**
*in* absmax:**T1**
*out* Y:**T1**|1+|**T1** = tensor(float)
**T2** = tensor(uint8)| |MatMulFpQ4|*in* A:**T1**
*in* B:**T2**
*in* B_shape:**T3**
*out* Y:**T1**|1+|**T1** = tensor(float)
**T2** = tensor(uint8)
**T3** = tensor(int64)| @@ -528,7 +528,7 @@ Do not modify directly.* |MatMulIntegerToFloat|*in* A:**T1**
*in* B:**T2**
*in* a_scale:**T3**
*in* b_scale:**T3**
*in* a_zero_point:**T1**
*in* b_zero_point:**T2**
*in* bias:**T3**
*out* Y:**T3**|1+|**T1** = tensor(int8), tensor(uint8)
**T2** = tensor(int8), tensor(uint8)
**T3** = tensor(float)| |MatMulNBits|*in* A:**T1**
*in* B:**T2**
*in* scales:**T1**
*in* zero_points:**T3**
*in* g_idx:**T4**
*in* bias:**T1**
*out* Y:**T1**|1+|**T1** = tensor(float), tensor(float16)
**T2** = tensor(uint8)
**T3** = tensor(float), tensor(float16), tensor(uint8)
**T4** = tensor(int32)| |MaxpoolWithMask|*in* X:**T**
*in* M:**tensor(int32)**
*out* Y:**T**|1+|**T** = tensor(float)| -|MultiHeadAttention|*in* query:**T**
*in* key:**T**
*in* value:**T**
*in* bias:**T**
*in* key_padding_mask:**M**
*in* attention_bias:**T**
*in* past_key:**T**
*in* past_value:**T**
*out* output:**T**
*out* present_key:**T**
*out* present_value:**T**|1+|**T** = tensor(float)| +|MultiHeadAttention|*in* query:**T**
*in* key:**T**
*in* value:**T**
*in* bias:**T**
*in* key_padding_mask:**M**
*in* attention_bias:**T**
*in* past_key:**T**
*in* past_value:**T**
*in* past_sequence_length:**M**
*in* cache_indirection:**M**
*out* output:**T**
*out* present_key:**T**
*out* present_value:**T**
*out* qk:**QK**|1+|**T** = tensor(float)| |MurmurHash3|*in* X:**T1**
*out* Y:**T2**|1+|**T1** = tensor(double), tensor(float), tensor(int32), tensor(int64), tensor(string), tensor(uint32), tensor(uint64)
**T2** = tensor(int32), tensor(uint32)| |NGramRepeatBlock|*in* input_ids:**Tid**
*in* scores:**T**
*out* scores_out:**T**|1+|**T** = tensor(float)
**Tid** = tensor(int64)| |NhwcMaxPool|*in* x:**T**
*out* y:**T**|1+|**T** = tensor(int8), tensor(uint8)| @@ -551,7 +551,7 @@ Do not modify directly.* |Sampling|*in* input_ids:**I**
*in* max_length:**I**
*in* min_length:**I**
*in* repetition_penalty:**T**
*in* vocab_mask:**I**
*in* prefix_vocab_mask:**I**
*in* attention_mask:**I**
*in* presence_mask:**I**
*in* seed:**I**
*out* sequences:**I**
*out* filtered_logits:**T**|1+|**T** = tensor(float)| |SkipLayerNormalization|*in* input:**T**
*in* skip:**T**
*in* gamma:**T**
*in* beta:**T**
*in* bias:**T**
*out* output:**T**
*out* mean:**U**
*out* inv_std_var:**U**
*out* input_skip_bias_sum:**T**|1+|**T** = tensor(double), tensor(float), tensor(float16)| |SkipSimplifiedLayerNormalization|*in* input:**T**
*in* skip:**T**
*in* gamma:**T**
*in* bias:**T**
*out* output:**T**
*out* mean:**U**
*out* inv_std_var:**U**
*out* input_skip_bias_sum:**T**|1+|**T** = tensor(double), tensor(float), tensor(float16)| -|SparseAttention|*in* query:**T**
*in* key:**T**
*in* value:**T**
*in* past_key:**T**
*in* past_value:**T**
*in* block_row_indices:**M**
*in* block_col_indices:**M**
*in* total_sequence_length:**M**
*in* key_total_sequence_lengths:**M**
*in* cos_cache:**T**
*in* sin_cache:**T**
*out* output:**T**
*out* present_key:**T**
*out* present_value:**T**|1+|**M** = tensor(int32)
**T** = tensor(float)| +|SparseAttention|*in* query:**T**
*in* key:**T**
*in* value:**T**
*in* past_key:**T**
*in* past_value:**T**
*in* block_row_indices:**M**
*in* block_col_indices:**M**
*in* total_sequence_length:**M**
*in* key_total_sequence_lengths:**M**
*in* cos_cache:**T**
*in* sin_cache:**T**
*out* output:**T**
*out* present_key:**T**
*out* present_value:**T**|1+|**M** = tensor(int32)
**T** = tensor(float), tensor(float16)| |SparseToDenseMatMul|*in* A:**T**
*in* B:**T1**
*out* Y:**T1**|1+|**T** = sparse_tensor(double), sparse_tensor(float), sparse_tensor(int32), sparse_tensor(int64), sparse_tensor(uint32), sparse_tensor(uint64)
**T1** = tensor(double), tensor(float), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| |Tokenizer|*in* X:**T**
*out* Y:**T**|1+|**T** = tensor(string)| |TransposeMatMul|*in* A:**T**
*in* B:**T**
*out* Y:**T**|1+|**T** = tensor(float)| @@ -582,7 +582,7 @@ Do not modify directly.* | Op Name | Parameters | OpSet Version | Types Supported | |---------|------------|---------------|-----------------| |**Operator Domain:** *ai.onnx*|||| -|Abs|*in* X:**T**
*out* Y:**T**|13+|**T** = tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|Abs|*in* X:**T**
*out* Y:**T**|13+|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |||[6, 12]|**T** = tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |Add|*in* A:**T**
*in* B:**T**
*out* C:**T**|14+|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |||13|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| @@ -839,7 +839,7 @@ Do not modify directly.* |Shrink|*in* input:**T**
*out* output:**T**|9+|**T** = tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |Sigmoid|*in* X:**T**
*out* Y:**T**|13+|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16)| |||[6, 12]|**T** = tensor(double), tensor(float), tensor(float16)| -|Sign|*in* input:**T**
*out* output:**T**|13+|**T** = tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|Sign|*in* input:**T**
*out* output:**T**|13+|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |SimplifiedLayerNormalization|*in* X:**T**
*in* scale:**V**
*out* Y:**V**
*out* inv_std_var:**U**|1+|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16)
**U** = tensor(double), tensor(float)
**V** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16)| |Sin|*in* input:**T**
*out* output:**T**|7+|**T** = tensor(double), tensor(float), tensor(float16)| |Size|*in* data:**T**
*out* size:**T1**|13+|**T** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T1** = tensor(int64)| @@ -906,7 +906,7 @@ Do not modify directly.* |ComplexMulConj|*in* A:**T**
*in* B:**T**
*out* C:**T**|1+|**T** = tensor(float), tensor(float16)| |ConvTransposeWithDynamicPads|*in* X:**T**
*in* W:**T**
*in* Pads:**tensor(int64)**
*in* B:**T**
*out* Y:**T**|1+|**T** = tensor(float)| |DecoderAttention|*in* query:**T**
*in* key:**T**
*in* q_weight:**T**
*in* kv_weight:**T**
*in* bias:**T**
*in* key_padding_mask:**B**
*in* key_cache:**T**
*in* value_cache:**T**
*in* static_kv:**B**
*in* use_past:**B**
*in* has_layer_state:**B**
*in* has_key_padding_mask:**B**
*out* output:**T**
*out* new_key_cache:**T**
*out* new_value_cache:**T**|1+|**T** = tensor(float), tensor(float16)| -|DecoderMaskedMultiHeadAttention|*in* query:**T**
*in* key:**T**
*in* value:**T**
*in* mask_index:**M**
*in* attention_bias:**T**
*in* past_key:**T**
*in* past_value:**T**
*in* past_sequence_length:**M**
*in* beam_width:**M**
*in* cache_indirection:**M**
*in* bias:**T**
*out* output:**T**
*out* present_key:**T**
*out* present_value:**T**
*out* qk:**V**|1+|**T** = tensor(float), tensor(float16)| +|DecoderMaskedMultiHeadAttention|*in* query:**T**
*in* key:**T**
*in* value:**T**
*in* mask_index:**M**
*in* attention_bias:**T**
*in* past_key:**T**
*in* past_value:**T**
*in* past_sequence_length:**M**
*in* beam_width:**M**
*in* cache_indirection:**M**
*in* bias:**T**
*out* output:**T**
*out* present_key:**T**
*out* present_value:**T**
*out* qk:**QK**|1+|**QK** = tensor(float), tensor(float16)
**T** = tensor(float), tensor(float16)| |DecoderMaskedSelfAttention|*in* input:**T**
*in* weights:**T**
*in* bias:**T**
*in* mask_index:**M**
*in* past:**T**
*in* attention_bias:**T**
*in* past_sequence_length:**M**
*in* beam_width:**M**
*in* cache_indirection:**M**
*out* output:**T**
*out* present:**T**|1+|**T** = tensor(float), tensor(float16)| |DequantizeLinear|*in* x:**T1**
*in* x_scale:**T2**
*in* x_zero_point:**T1**
*out* y:**T2**|1+|**T1** = tensor(int8), tensor(uint8)
**T2** = tensor(float16)| |DequantizeWithOrder|*in* input:**Q**
*in* scale_input:**S**
*out* output:**F**|1+|**F** = tensor(float), tensor(float16)
**Q** = tensor(int8)
**S** = tensor(float)| @@ -922,14 +922,14 @@ Do not modify directly.* |GreedySearch|*in* input_ids:**I**
*in* max_length:**I**
*in* min_length:**I**
*in* repetition_penalty:**T**
*in* vocab_mask:**I**
*in* prefix_vocab_mask:**I**
*in* attention_mask:**I**
*out* sequences:**I**|1+|**T** = tensor(float), tensor(float16)| |GridSample|*in* X:**T1**
*in* Grid:**T1**
*out* Y:**T2**|1+|**T1** = tensor(float)
**T2** = tensor(float)| |GroupNorm|*in* X:**T**
*in* gamma:**M**
*in* beta:**M**
*out* Y:**T**|1+|**T** = tensor(float), tensor(float16)| -|GroupQueryAttention|*in* query:**T**
*in* key:**T**
*in* value:**T**
*in* past_key:**T**
*in* past_value:**T**
*in* seqlens_k:**M**
*in* total_sequence_length:**M**
*in* cos_cache:**T**
*in* sin_cache:**T**
*out* output:**T**
*out* present_key:**T**
*out* present_value:**T**|1+|**M** = tensor(int32)
**T** = tensor(bfloat16), tensor(float16)| +|GroupQueryAttention|*in* query:**T**
*in* key:**T**
*in* value:**T**
*in* past_key:**T**
*in* past_value:**T**
*in* seqlens_k:**M**
*in* total_sequence_length:**M**
*in* cos_cache:**T**
*in* sin_cache:**T**
*in* position_ids:**tensor(int64)**
*in* attention_bias:**T**
*out* output:**T**
*out* present_key:**T**
*out* present_value:**T**|1+|**M** = tensor(int32)
**T** = tensor(bfloat16), tensor(float16)| |Inverse|*in* X:**T**
*out* Y:**T**|1+|**T** = tensor(double), tensor(float), tensor(float16)| |Irfft|*in* X:**T**
*out* Y:**T**|1+|**T** = tensor(double), tensor(float), tensor(float16)| |LongformerAttention|*in* input:**T**
*in* weight:**T**
*in* bias:**T**
*in* mask:**T**
*in* global_weight:**T**
*in* global_bias:**T**
*in* global:**G**
*out* output:**T**|1+|**T** = tensor(float), tensor(float16)| |MatMulBnb4|*in* A:**T1**
*in* B:**T2**
*in* absmax:**T1**
*out* Y:**T1**|1+|**T1** = tensor(bfloat16), tensor(float), tensor(float16)
**T2** = tensor(uint8)| |MatMulNBits|*in* A:**T1**
*in* B:**T2**
*in* scales:**T1**
*in* zero_points:**T3**
*in* g_idx:**T4**
*in* bias:**T1**
*out* Y:**T1**|1+|**T1** = tensor(float), tensor(float16)
**T2** = tensor(uint8)| |MoE|*in* input:**T**
*in* router_probs:**T**
*in* fc1_experts_weights:**T**
*in* fc1_experts_bias:**T**
*in* fc2_experts_weights:**T**
*in* fc2_experts_bias:**T**
*in* fc3_experts_weights:**T**
*in* fc3_experts_bias:**T**
*out* output:**T**|1+|**T** = tensor(float), tensor(float16)| -|MultiHeadAttention|*in* query:**T**
*in* key:**T**
*in* value:**T**
*in* bias:**T**
*in* key_padding_mask:**M**
*in* attention_bias:**T**
*in* past_key:**T**
*in* past_value:**T**
*out* output:**T**
*out* present_key:**T**
*out* present_value:**T**|1+|**T** = tensor(float), tensor(float16)| +|MultiHeadAttention|*in* query:**T**
*in* key:**T**
*in* value:**T**
*in* bias:**T**
*in* key_padding_mask:**M**
*in* attention_bias:**T**
*in* past_key:**T**
*in* past_value:**T**
*in* past_sequence_length:**M**
*in* cache_indirection:**M**
*out* output:**T**
*out* present_key:**T**
*out* present_value:**T**
*out* qk:**QK**|1+|**QK** = tensor(float), tensor(float16)
**T** = tensor(float), tensor(float16)| |NGramRepeatBlock|*in* input_ids:**Tid**
*in* scores:**T**
*out* scores_out:**T**|1+|**T** = tensor(float)
**Tid** = tensor(int64)| |NhwcConv|*in* X:**T**
*in* W:**T**
*in* B:**T**
*out* Y:**T**|1+|**T** = tensor(float), tensor(float16)| |PackedAttention|*in* input:**T**
*in* weights:**T**
*in* bias:**T**
*in* token_offset:**M**
*in* cumulative_sequence_length:**M**
*in* attention_bias:**T**
*out* output:**T**|1+|**T** = tensor(float), tensor(float16)| @@ -1399,10 +1399,10 @@ Do not modify directly.* |FusedMatMulActivation|*in* A:**T**
*in* B:**T**
*out* Y:**T**|1+|**T** = tensor(float), tensor(float16)| |Gelu|*in* X:**T**
*out* Y:**T**|1+|**T** = tensor(float), tensor(float16)| |GroupNorm|*in* X:**T**
*in* gamma:**M**
*in* beta:**M**
*out* Y:**T**|1+|**M** = tensor(float), tensor(float16)
**T** = tensor(float), tensor(float16)| -|GroupQueryAttention|*in* query:**T**
*in* key:**T**
*in* value:**T**
*in* past_key:**T**
*in* past_value:**T**
*in* seqlens_k:**M**
*in* total_sequence_length:**M**
*in* cos_cache:**T**
*in* sin_cache:**T**
*out* output:**T**
*out* present_key:**T**
*out* present_value:**T**|1+|**M** = tensor(int32)
**T** = tensor(float), tensor(float16)| +|GroupQueryAttention|*in* query:**T**
*in* key:**T**
*in* value:**T**
*in* past_key:**T**
*in* past_value:**T**
*in* seqlens_k:**M**
*in* total_sequence_length:**M**
*in* cos_cache:**T**
*in* sin_cache:**T**
*in* position_ids:**tensor(int64)**
*in* attention_bias:**T**
*out* output:**T**
*out* present_key:**T**
*out* present_value:**T**|1+|**M** = tensor(int32)
**T** = tensor(float), tensor(float16)| |MatMulIntegerToFloat|*in* A:**T1**
*in* B:**T2**
*in* a_scale:**T3**
*in* b_scale:**T3**
*in* a_zero_point:**T1**
*in* b_zero_point:**T2**
*in* bias:**T3**
*out* Y:**T3**|1+|**T1** = tensor(int8), tensor(uint8)
**T2** = tensor(int8), tensor(uint8)
**T3** = tensor(float), tensor(float16)| |MatMulNBits|*in* A:**T1**
*in* B:**T2**
*in* scales:**T1**
*in* zero_points:**T3**
*in* g_idx:**T4**
*in* bias:**T1**
*out* Y:**T1**|1+|**T1** = tensor(float), tensor(float16)
**T2** = tensor(uint8)| -|MultiHeadAttention|*in* query:**T**
*in* key:**T**
*in* value:**T**
*in* bias:**T**
*in* key_padding_mask:**M**
*in* attention_bias:**T**
*in* past_key:**T**
*in* past_value:**T**
*out* output:**T**
*out* present_key:**T**
*out* present_value:**T**|1+|**M** = tensor(int32)
**T** = tensor(float), tensor(float16)| +|MultiHeadAttention|*in* query:**T**
*in* key:**T**
*in* value:**T**
*in* bias:**T**
*in* key_padding_mask:**M**
*in* attention_bias:**T**
*in* past_key:**T**
*in* past_value:**T**
*in* past_sequence_length:**M**
*in* cache_indirection:**M**
*out* output:**T**
*out* present_key:**T**
*out* present_value:**T**
*out* qk:**QK**|1+|**M** = tensor(int32)
**T** = tensor(float), tensor(float16)| |NhwcConv|*in* X:**T**
*in* W:**T**
*in* B:**T**
*out* Y:**T**|1+|**T** = tensor(float), tensor(float16)| |QAttention|*in* input:**T1**
*in* weight:**T2**
*in* bias:**T3**
*in* input_scale:**T3**
*in* weight_scale:**T3**
*in* mask_index:**T4**
*in* input_zero_point:**T1**
*in* weight_zero_point:**T2**
*in* past:**T3**
*out* output:**T3**
*out* present:**T3**|1+|**T1** = tensor(int8), tensor(uint8)
**T2** = tensor(int8), tensor(uint8)
**T3** = tensor(float), tensor(float16)
**T4** = tensor(int32)| |QLinearAdd|*in* A:**T**
*in* A_scale:**tensor(float)**
*in* A_zero_point:**T**
*in* B:**T**
*in* B_scale:**tensor(float)**
*in* B_zero_point:**T**
*in* C_scale:**tensor(float)**
*in* C_zero_point:**T**
*out* C:**T**|1+|**T** = tensor(int8), tensor(uint8)| diff --git a/docs/python/README.rst b/docs/python/README.rst index cce966f7d7d0c..dbffd1d32c052 100644 --- a/docs/python/README.rst +++ b/docs/python/README.rst @@ -8,6 +8,11 @@ For more information on ONNX Runtime, please see `aka.ms/onnxruntime (status.Code())) + +#define ORT_THROW_WITH_CATEGORY_AND_CODE(category, code, ...) \ + throw ::onnxruntime::OnnxRuntimeException(ORT_WHERE_WITH_STACK, \ + ::onnxruntime::MakeString(__VA_ARGS__), \ + ::onnxruntime::common::category, \ + ::onnxruntime::common::code) + #endif #define ORT_MAKE_STATUS(category, code, ...) \ @@ -237,7 +267,7 @@ void LogRuntimeError(uint32_t session_id, const common::Status& status, const ch auto _status = (expr); \ if ((!_status.IsOK())) { \ ::onnxruntime::LogRuntimeError(0, _status, __FILE__, static_cast(__FUNCTION__), __LINE__); \ - ORT_THROW(_status); \ + ORT_THROW_FROM_STATUS(_status); \ } \ } while (0) diff --git a/include/onnxruntime/core/common/exceptions.h b/include/onnxruntime/core/common/exceptions.h index 494a770b8db98..6d0f6edd6e7c4 100644 --- a/include/onnxruntime/core/common/exceptions.h +++ b/include/onnxruntime/core/common/exceptions.h @@ -11,6 +11,7 @@ #include #include "core/common/common.h" +#include "core/common/status.h" #include "core/common/code_location.h" namespace onnxruntime { @@ -35,12 +36,44 @@ class OnnxRuntimeException : public std::exception { /** Create a new exception that captures the location it was thrown from. @param location Location in the source code the exception is being thrown from + @param msg Message containing additional information about the exception cause. + @param category Error category + @param code Error code + */ + + OnnxRuntimeException(const CodeLocation& location, + const std::string& message, + common::StatusCategory category, + common::StatusCode code) noexcept + : OnnxRuntimeException(location, nullptr, message, category, code) { + } + + /** + Create a new exception that captures the location it was thrown from. + The instance will be created with ONNXRUNTIME category and FAIL code. + @param location Location in the source code the exception is being thrown from @param failed_condition Optional string containing the condition that failed. e.g. "tensor.Size() == input.Size()". May be nullptr. @param msg Message containing additional information about the exception cause. */ - OnnxRuntimeException(const CodeLocation& location, const char* failed_condition, const std::string& msg) - : location_{location} { + OnnxRuntimeException(const CodeLocation& location, const char* failed_condition, const std::string& msg) noexcept + : OnnxRuntimeException(location, failed_condition, msg, + common::StatusCategory::ONNXRUNTIME, common::StatusCode::FAIL) { + } + + /** + Create a new exception that captures the location it was thrown from. + @param location Location in the source code the exception is being thrown from + @param failed_condition Optional string containing the condition that failed. + e.g. "tensor.Size() == input.Size()". May be nullptr. + @param msg Message containing additional information about the exception cause. + @param category Error category + @param code Error code + */ + OnnxRuntimeException(const CodeLocation& location, const char* failed_condition, const std::string& msg, + common::StatusCategory category, + common::StatusCode code) + : location_{location}, category_(category), code_(code) { std::ostringstream ss; ss << location.ToString(CodeLocation::kFilenameAndPath); // output full path in case just the filename is ambiguous @@ -58,6 +91,14 @@ class OnnxRuntimeException : public std::exception { what_ = ss.str(); } + common::StatusCategory Category() const noexcept { + return category_; + } + + common::StatusCode Code() const noexcept { + return code_; + } + const char* what() const noexcept override { return what_.c_str(); } @@ -66,6 +107,8 @@ class OnnxRuntimeException : public std::exception { const CodeLocation location_; const std::vector stacktrace_; std::string what_; + common::StatusCategory category_; + common::StatusCode code_; }; } // namespace onnxruntime diff --git a/include/onnxruntime/core/common/status.h b/include/onnxruntime/core/common/status.h index 8f171daabbb1e..b222e411d7804 100644 --- a/include/onnxruntime/core/common/status.h +++ b/include/onnxruntime/core/common/status.h @@ -43,7 +43,8 @@ enum StatusCode { MODEL_LOADED = 8, NOT_IMPLEMENTED = 9, INVALID_GRAPH = 10, - EP_FAIL = 11 + EP_FAIL = 11, + MODEL_LOAD_CANCELED = 12, }; constexpr const char* StatusCodeToString(StatusCode status) noexcept { @@ -72,6 +73,8 @@ constexpr const char* StatusCodeToString(StatusCode status) noexcept { return "INVALID_GRAPH"; case StatusCode::EP_FAIL: return "EP_FAIL"; + case StatusCode::MODEL_LOAD_CANCELED: + return "MODEL_LOAD_CANCELED"; default: return "GENERAL ERROR"; } @@ -104,6 +107,8 @@ constexpr HRESULT StatusCodeToHRESULT(StatusCode status) noexcept { return HRESULT_FROM_WIN32(ERROR_FILE_CORRUPT); case StatusCode::EP_FAIL: return HRESULT_FROM_WIN32(ERROR_INTERNAL_ERROR); + case StatusCode::MODEL_LOAD_CANCELED: + return HRESULT_FROM_WIN32(ERROR_CANCELLED); default: return E_FAIL; } diff --git a/include/onnxruntime/core/framework/execution_provider.h b/include/onnxruntime/core/framework/execution_provider.h index c9a15de9ef897..2245ff5791feb 100644 --- a/include/onnxruntime/core/framework/execution_provider.h +++ b/include/onnxruntime/core/framework/execution_provider.h @@ -20,6 +20,7 @@ struct ComputeCapability; class KernelRegistry; struct KernelCreateInfo; class Node; +class GraphOptimizerRegistry; } // namespace onnxruntime #else #include @@ -129,10 +130,25 @@ class IExecutionProvider { and decide whether a node will be assigned to <*this> execution provider. For kernels registered in a kernel registry, `kernel_lookup` must be used to find a matching kernel for this EP. + + The graph_optimizer_registry is designed for enabling L2+ graph optimizations tailored for EPs. + These optimizations are applied after the graph partitioner assigns ComputeCapability to the EP + and before EP's "Compile" or fusion. + + Steps to use graph_optimizer_registry and create the optimization ComputeCapability: + 1. Lookup Optimizer: The EP calls provider bridge API to lookup pre-defined optimizer by name and get selection function. + - Example: g_host->GetOptimizerByName(optimizer_name, graph_optimizer_registry, selection_func) + 2. Run Selection Function: The EP executes the selection function to obtain the selection ComputeCapability. + - ComputeCapability.optimize_func would be set by the optimizer to the function that does the optimization. + 3. Create Optimization ComputeCapability: The EP uses the selection ComputeCapability to create the optimization ComputeCapability. + 4. Return ComputeCapability: The EP returns the final ComputeCapability, with nodes_to_optimize set to the optimization ComputeCapability. + + Note: For more detailed implementations of using graph_optimizer_registry, please refer to TensorRT EP. */ virtual std::vector> GetCapability(const onnxruntime::GraphViewer& graph_viewer, const IKernelLookup& kernel_lookup, + const GraphOptimizerRegistry& graph_optimizer_registry, IResourceAccountant* resource_accountant = nullptr) const; /** diff --git a/include/onnxruntime/core/framework/stream_handles.h b/include/onnxruntime/core/framework/stream_handles.h index 01631e1fb2aa6..402ea2da2148c 100644 --- a/include/onnxruntime/core/framework/stream_handles.h +++ b/include/onnxruntime/core/framework/stream_handles.h @@ -3,6 +3,7 @@ #pragma once #include +#include #include #include "core/framework/allocator.h" #include "core/framework/ortdevice.h" @@ -154,6 +155,12 @@ class Notification { // TODO: use a better way to dispatch handles. using CreateStreamFn = std::function(const OrtDevice&)>; +// This SetDevice function is used by TRT EP or CUDA EP to handle the case where ExecutionMode::ORT_PARALLEL is enabled. +// In that case, ORT retrieves a thread from the thread pool to run kernels for a given session. +// Since new threads default to using device 0, but the session may be tightly bound to a device > 0, +// This SetDevice function will be called in RunSince to ensure running kernels on a correct GPU device. +using SetDeviceFn = std::function; + // an interface of a simple registry which hold the handles EP registered. // make it interface so we can pass it through shared library based execution providers class IStreamCommandHandleRegistry { @@ -171,6 +178,20 @@ class IStreamCommandHandleRegistry { WaitNotificationFn fn) = 0; // register a handle about how to create stream on given device type. virtual void RegisterCreateStreamFn(OrtDevice::DeviceType device_type, CreateStreamFn f) = 0; + + // Register a SetDevice function. + // This interface is currently used by TRT EP or CUDA EP only. + virtual void RegisterSetDeviceFn(OrtDevice::DeviceType device_type, SetDeviceFn f) { + ORT_UNUSED_PARAMETER(device_type); + ORT_UNUSED_PARAMETER(f); + }; + + // Get a SetDevice function. + // This interface is currently used by TRT EP or CUDA EP only and is called in RunSince from stream execution. + virtual std::optional GetSetDeviceFn(OrtDevice::DeviceType device_type) const { + ORT_UNUSED_PARAMETER(device_type); + return std::nullopt; + }; }; } // namespace onnxruntime diff --git a/include/onnxruntime/core/graph/graph.h b/include/onnxruntime/core/graph/graph.h index 7798394b045dc..35b568e3f8e28 100644 --- a/include/onnxruntime/core/graph/graph.h +++ b/include/onnxruntime/core/graph/graph.h @@ -27,6 +27,7 @@ #include "core/common/span_utils.h" #include "core/common/status.h" #include "core/common/logging/logging.h" +#include "core/framework/ort_value.h" #include "core/framework/prepacked_weights_container.h" #include "core/graph/onnx_protobuf.h" #include "core/graph/basic_types.h" @@ -39,6 +40,9 @@ #include "core/graph/node_arg.h" #include "core/graph/ort_format_load_options.h" +// Type from Model Editor API in ORT C API so can't be in a namespace +struct OrtGraph; + namespace onnxruntime { class Graph; struct IndexedSubGraph; @@ -763,6 +767,10 @@ class Graph { // NOLINT(clang-analyzer-optin.performance.Padding): preserve exi */ bool GetInitializedTensor(const std::string& tensor_name, const ONNX_NAMESPACE::TensorProto*& value) const; + /** Populate `value` if an externally allocated OrtValue exists for an initializer with the given name. + */ + bool GetOrtValueInitializer(const std::string& name, OrtValue& value) const; + /** Gets all the initializer tensors in this Graph. */ const InitializedTensorSet& GetAllInitializedTensors() const noexcept { return name_to_initial_tensor_; } @@ -1430,6 +1438,16 @@ class Graph { // NOLINT(clang-analyzer-optin.performance.Padding): preserve exi const OrtFormatLoadOptions& load_options, const logging::Logger& logger, std::unique_ptr& graph); + static Status LoadFromModelEditorApiModel(const OrtGraph& api_graph, + const Model& owning_model, + const std::unordered_map& domain_to_version, + IOnnxRuntimeOpSchemaCollectionPtr schema_registry, + bool strict_shape_type_inference, + const logging::Logger& logger, + std::unique_ptr& graph); + + Status UpdateUsingModelEditorApiModel(const OrtModel& api_model); + #if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) const RuntimeOptimizationRecordContainer& RuntimeOptimizations() const { return runtime_optimizations_; @@ -1630,7 +1648,8 @@ class Graph { // NOLINT(clang-analyzer-optin.performance.Padding): preserve exi // Implementation for initializer replacement Status ReplaceInitializedTensorImpl(ONNX_NAMESPACE::TensorProto new_initializer, bool is_external); - std::vector CreateNodeArgs(const google::protobuf::RepeatedPtrField& names, + template // range-initializer returning std::string + std::vector CreateNodeArgs(const StringRange& names, const ArgNameToTypeMap& name_to_type_map); void ToGraphProtoInternal(ONNX_NAMESPACE::GraphProto& graph_proto) const; @@ -1694,6 +1713,8 @@ class Graph { // NOLINT(clang-analyzer-optin.performance.Padding): preserve exi return nodes_[node_index].get(); } + Status LoadFromModelEditorApiModel(const OrtGraph& api_graph, bool updating_existing_graph = false); + const Model& owning_model_; // GraphProto to store name, version, initializer. @@ -1708,6 +1729,12 @@ class Graph { // NOLINT(clang-analyzer-optin.performance.Padding): preserve exi InitializedTensorSet name_to_initial_tensor_; + // Initializers that are external to the Graph. + // e.g. created from existing memory using CreateTensorWithDataAndDeleterAsOrtValue in the ORT API. + // As we need to convert to TensorProto for the optimizers to work and keep the deleter information we store them + // in the Graph instance and retrieve during session state finalization. + std::unordered_map ortvalue_initializers_; + std::unordered_set, std::hash, std::equal_to> sparse_tensor_names_; @@ -1744,6 +1771,7 @@ class Graph { // NOLINT(clang-analyzer-optin.performance.Padding): preserve exi // in some case, a fused sub-graph will happens multiple times in one model, we use a map // to store reusable-schema in lookup. InlinedHashMap> reusable_fused_schema_map_; + #endif // !defined(ORT_MINIMAL_BUILD) // Graph nodes. @@ -1806,7 +1834,7 @@ class Graph { // NOLINT(clang-analyzer-optin.performance.Padding): preserve exi std::unordered_map> node_arg_to_consumer_nodes_; #endif // !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) - const std::unordered_map domain_to_version_; + std::unordered_map domain_to_version_; // Model IR version. Version ir_version_{ONNX_NAMESPACE::Version::IR_VERSION}; diff --git a/include/onnxruntime/core/graph/graph_viewer.h b/include/onnxruntime/core/graph/graph_viewer.h index 9385e2f092e58..6a664d8be9c05 100644 --- a/include/onnxruntime/core/graph/graph_viewer.h +++ b/include/onnxruntime/core/graph/graph_viewer.h @@ -193,6 +193,12 @@ class GraphViewer { IOnnxRuntimeOpSchemaCollectionPtr GetSchemaRegistry() const { return graph_->GetSchemaRegistry(); } #endif + /** Populate `value` if an externally allocated OrtValue exists for an initializer with the given name. + */ + bool GetOrtValueInitializer(const std::string& name, OrtValue& value) const { + return graph_->GetOrtValueInitializer(name, value); + } + private: ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(GraphViewer); GraphViewer(const Graph& graph, const IndexedSubGraph* filter_info); diff --git a/include/onnxruntime/core/graph/indexed_sub_graph.h b/include/onnxruntime/core/graph/indexed_sub_graph.h index e457d3dcad1f1..088db79a7e005 100644 --- a/include/onnxruntime/core/graph/indexed_sub_graph.h +++ b/include/onnxruntime/core/graph/indexed_sub_graph.h @@ -72,6 +72,12 @@ struct IndexedSubGraph { return meta_def_.get(); } + /** Gets the mutable meta definition needed to represent this subgraph as a FunctionProto. + @returns MetaDef instance if it has been set. nullptr if not. */ + MetaDef* GetMutableMetaDef() { + return meta_def_.get(); + } + // Check if the accounting is enabled for the current EP bool IsAccountingEnabled() const { return resource_accountant != nullptr && diff --git a/include/onnxruntime/core/providers/tensorrt/tensorrt_provider_options.h b/include/onnxruntime/core/providers/tensorrt/tensorrt_provider_options.h index f6a5d05d0e790..687f74c94f154 100644 --- a/include/onnxruntime/core/providers/tensorrt/tensorrt_provider_options.h +++ b/include/onnxruntime/core/providers/tensorrt/tensorrt_provider_options.h @@ -42,13 +42,15 @@ struct OrtTensorRTProviderOptionsV2 { int trt_sparsity_enable{0}; // Control if sparsity can be used by TRT. Default 0 = false, 1 = true int trt_builder_optimization_level{3}; // Set the builder optimization level. WARNING: levels below 3 do not guarantee good engine performance, but greatly improve build time. Default 3, valid range [0-5] int trt_auxiliary_streams{-1}; // Set maximum number of auxiliary streams per inference stream. Setting this value to 0 will lead to optimal memory usage. Default -1 = heuristics - const char* trt_tactic_sources{nullptr}; // pecify the tactics to be used by adding (+) or removing (-) tactics from the default + const char* trt_tactic_sources{nullptr}; // Specify the tactics to be used by adding (+) or removing (-) tactics from the default // tactic sources (default = all available tactics) e.g. "-CUDNN,+CUBLAS" available keys: "CUBLAS"|"CUBLAS_LT"|"CUDNN"|"EDGE_MASK_CONVOLUTIONS" - const char* trt_extra_plugin_lib_paths{nullptr}; // specify extra TensorRT plugin library paths + const char* trt_extra_plugin_lib_paths{nullptr}; // Specify extra TensorRT plugin library paths const char* trt_profile_min_shapes{nullptr}; // Specify the range of the input shapes to build the engine with const char* trt_profile_max_shapes{nullptr}; // Specify the range of the input shapes to build the engine with const char* trt_profile_opt_shapes{nullptr}; // Specify the range of the input shapes to build the engine with int trt_cuda_graph_enable{0}; // Enable CUDA graph in ORT TRT + const char* trt_preview_features{nullptr}; // Specify the preview features to be enabled, features should be separated by comma + // available keys: "ALIASED_PLUGIN_IO_10_03" /* * Please note that there are rules for using following context model related provider options: diff --git a/include/onnxruntime/core/session/onnxruntime_c_api.h b/include/onnxruntime/core/session/onnxruntime_c_api.h index b2f3d95e00a88..3bf0d5e19c525 100644 --- a/include/onnxruntime/core/session/onnxruntime_c_api.h +++ b/include/onnxruntime/core/session/onnxruntime_c_api.h @@ -38,7 +38,7 @@ * * This value is used by some API functions to behave as this version of the header expects. */ -#define ORT_API_VERSION 21 +#define ORT_API_VERSION 22 #ifdef __cplusplus extern "C" { @@ -255,6 +255,7 @@ typedef enum OrtErrorCode { ORT_NOT_IMPLEMENTED, ORT_INVALID_GRAPH, ORT_EP_FAIL, + ORT_MODEL_LOAD_CANCELED, } OrtErrorCode; typedef enum OrtOpAttrType { @@ -305,8 +306,12 @@ ORT_RUNTIME_CLASS(OpAttr); ORT_RUNTIME_CLASS(Logger); ORT_RUNTIME_CLASS(ShapeInferContext); ORT_RUNTIME_CLASS(LoraAdapter); +ORT_RUNTIME_CLASS(ValueInfo); +ORT_RUNTIME_CLASS(Node); +ORT_RUNTIME_CLASS(Graph); +ORT_RUNTIME_CLASS(Model); -#ifdef _WIN32 +#ifdef _MSC_VER typedef _Return_type_success_(return == 0) OrtStatus* OrtStatusPtr; #else typedef OrtStatus* OrtStatusPtr; @@ -665,6 +670,9 @@ typedef struct OrtApi OrtApi; struct OrtTrainingApi; typedef struct OrtTrainingApi OrtTrainingApi; +struct OrtModelEditorApi; +typedef struct OrtModelEditorApi OrtModelEditorApi; + /** \brief The helper interface to get the right version of OrtApi * * Get a pointer to this structure through ::OrtGetApiBase @@ -847,7 +855,8 @@ struct OrtApi { * * \snippet{doc} snippets.dox OrtStatus Return Value */ - ORT_API2_STATUS(CreateSessionFromArray, _In_ const OrtEnv* env, _In_ const void* model_data, size_t model_data_length, + ORT_API2_STATUS(CreateSessionFromArray, _In_ const OrtEnv* env, + _In_ const void* model_data, size_t model_data_length, _In_ const OrtSessionOptions* options, _Outptr_ OrtSession** out); /** \brief Run the model in an ::OrtSession @@ -1340,6 +1349,8 @@ struct OrtApi { * Create a tensor with user's buffer. You can fill the buffer either before calling this function or after. * p_data is owned by caller. ReleaseValue won't release p_data. * + * If you wish to transfer ownership of p_data to ORT use CreateTensorWithDataAndDeleterAsOrtValue. + * * \param[in] info Memory description of where the p_data buffer resides (CPU vs GPU etc). * \param[in] p_data Pointer to the data buffer. * \param[in] p_data_len The number of bytes in the data buffer. @@ -1997,7 +2008,8 @@ struct OrtApi { /** \brief Get the value type from an ::OrtMapTypeInfo * * \param[in] map_type_info - * \param[out] type_info + * \param[out] type_info A copy of the OrtTypeInfo for the map value type. + * The user must free this value with ReleaseTypeInfo. * * \snippet{doc} snippets.dox OrtStatus Return Value */ @@ -2012,7 +2024,8 @@ struct OrtApi { * This is used by WinML to support model reflection APIs. * * \param[in] sequence_type_info - * \param[out] type_info + * \param[out] type_info A copy of the OrtTypeInfo for the sequence element type. + * The user must free this value with ReleaseTypeInfo. * * \snippet{doc} snippets.dox OrtStatus Return Value */ @@ -2887,7 +2900,8 @@ struct OrtApi { * \snippet{doc} snippets.dox OrtStatus Return Value */ ORT_API2_STATUS(CreateSessionWithPrepackedWeightsContainer, _In_ const OrtEnv* env, _In_ const ORTCHAR_T* model_path, - _In_ const OrtSessionOptions* options, _Inout_ OrtPrepackedWeightsContainer* prepacked_weights_container, + _In_ const OrtSessionOptions* options, + _Inout_ OrtPrepackedWeightsContainer* prepacked_weights_container, _Outptr_ OrtSession** out); /** \brief Create session from memory with prepacked weights container @@ -2910,7 +2924,8 @@ struct OrtApi { */ ORT_API2_STATUS(CreateSessionFromArrayWithPrepackedWeightsContainer, _In_ const OrtEnv* env, _In_ const void* model_data, size_t model_data_length, - _In_ const OrtSessionOptions* options, _Inout_ OrtPrepackedWeightsContainer* prepacked_weights_container, + _In_ const OrtSessionOptions* options, + _Inout_ OrtPrepackedWeightsContainer* prepacked_weights_container, _Outptr_ OrtSession** out); /// @} @@ -3632,48 +3647,77 @@ struct OrtApi { * that should be used to add it. * * QNN supported keys: - * "backend_path": file path to QNN backend library. - * "profiling_level": QNN profiling level, options: "off", "basic", "detailed". Default to off. + * "backend_type": Type of QNN backend. Specifies a backend path that is the associated QNN backend library file + * name. E.g., given backend type "htp", on Windows, the backend path would be "QnnHtp.dll", and on other + * platforms, it would be "libQnnHtp.so". Mutually exclusive with "backend_path". + * Available options: + * - "cpu" + * - "gpu" + * - "htp": Default. + * - "saver" + * "backend_path": File path to QNN backend library. Mutually exclusive with "backend_type". + * "profiling_level": QNN profiling level. + * Available options: + * - "off": Default. + * - "basic" + * - "detailed" * "profiling_file_path": QNN profiling file path if ETW not enabled. * "rpc_control_latency": QNN RPC control latency. * "vtcm_mb": QNN VTCM size in MB. default to 0(not set). - * "htp_performance_mode": QNN performance mode, options: "burst", "balanced", "default", "high_performance", - * "high_power_saver", "low_balanced", "extreme_power_saver", "low_power_saver", "power_saver", "sustained_high_performance". Default to "default". + * "htp_performance_mode": QNN performance mode. + * Available options: + * - "burst" + * - "balanced" + * - "default": Default. + * - "high_performance" + * - "high_power_saver" + * - "low_balanced" + * - "extreme_power_saver" + * - "low_power_saver" + * - "power_saver" + * - "sustained_high_performance" * "qnn_saver_path": File path to the QNN Saver backend library. If specified, QNN Saver will be enabled and will - * dump QNN API calls to disk for replay/debugging. QNN Saver produces incorrect model inference results and - * may alter model/EP partitioning. Use only for debugging. - * "qnn_context_priority": QNN context priority, options: "low", "normal", "normal_high", "high". Default to "normal". - * "htp_graph_finalization_optimization_mode": Set the optimization mode for graph finalization on the HTP backend. Available options: - * - "0": Default. - * - "1": Faster preparation time, less optimal graph. - * - "2": Longer preparation time, more optimal graph. - * - "3": Longest preparation time, most likely even more optimal graph. See QNN SDK documentation for specific details. - * "soc_model": The SoC model number. Refer to the QNN SDK documentation for valid values. Defaults to "0" (unknown). - * "htp_arch": The minimum HTP architecture the driver will use to select compatible QNN operators. Available options: - * - "0": Default (none). - * - "68" - * - "69" - * - "73" - * - "75" + * dump QNN API calls to disk for replay/debugging. QNN Saver produces incorrect model inference results and + * may alter model/EP partitioning. Use only for debugging. + * "qnn_context_priority": QNN context priority. + * Available options: + * - "low" + * - "normal": Default. + * - "normal_high" + * - "high" + * "htp_graph_finalization_optimization_mode": Set the optimization mode for graph finalization on the HTP backend. + * Available options: + * - "0": Default. + * - "1": Faster preparation time, less optimal graph. + * - "2": Longer preparation time, more optimal graph. + * - "3": Longest preparation time, most likely even more optimal graph. See QNN SDK documentation for specific + * details. + * "soc_model": The SoC model number. Refer to the QNN SDK documentation for valid values. + * Defaults to "0" (unknown). + * "htp_arch": The minimum HTP architecture the driver will use to select compatible QNN operators. + * Available options: + * - "0": Default (none). + * - "68" + * - "69" + * - "73" + * - "75" * "device_id": The ID of the device to use when setting 'htp_arch'. Defaults to "0" (for single device). * "enable_htp_fp16_precision": Used for float32 model for HTP backend. - * Enable the float32 model to be inferenced with fp16 precision. Otherwise, it will be fp32 precision. + * Enable the float32 model to be inferenced with fp16 precision. Otherwise, it will be fp32 precision. * - "0": With fp32 precision. * - "1": Default. With fp16 precision. - * "enable_htp_weight_sharing": Enable QNN weight sharing feature while compiling multiple graphs into one QNN context. - * - "0": Default. Disabled. - * - "1": Enabled. * "offload_graph_io_quantization": Offload graph input quantization and graph output dequantization to another - * execution provider (typically CPU EP). - * - "0": Disabled. QNN EP will handle quantization and dequantization of graph I/O. - * - "1": Enabled. This is the default value. - * "enable_htp_spill_fill_buffer": Enable HTP spill fill buffer setting. The flag is used while generating context binary. - * - "0": Default. Disabled. - * - "1": Enabled. + * execution provider (typically CPU EP). + * - "0": Disabled. QNN EP will handle quantization and dequantization of graph I/O. + * - "1": Enabled. This is the default value. + * "enable_htp_spill_fill_buffer": Enable HTP spill fill buffer setting. The flag is used while generating context + * binary. + * - "0": Default. Disabled. + * - "1": Enabled. * "enable_htp_shared_memory_allocator": Enable the QNN HTP shared memory allocator. Requires libcdsprpc.so/dll to - * be available. - * - "0": Default. Disabled. - * - "1": Enabled. + * be available. + * - "0": Default. Disabled. + * - "1": Enabled. * "dump_json_qnn_graph": Set to "1" to dump QNN graphs generated by QNN EP as JSON files. Each graph partition * assigned to QNN EP is dumped to a separate file. * "json_qnn_graph_dir": Directory in which to dump QNN JSON graphs. If not specified, QNN graphs are dumped in the @@ -3681,18 +3725,18 @@ struct OrtApi { * * SNPE supported keys: * "runtime": SNPE runtime engine, options: "CPU", "CPU_FLOAT32", "GPU", "GPU_FLOAT32_16_HYBRID", "GPU_FLOAT16", - * "DSP", "DSP_FIXED8_TF", "AIP_FIXED_TF", "AIP_FIXED8_TF". - * Mapping to SNPE Runtime_t definition: CPU, CPU_FLOAT32 => zdl::DlSystem::Runtime_t::CPU; - * GPU, GPU_FLOAT32_16_HYBRID => zdl::DlSystem::Runtime_t::GPU; - * GPU_FLOAT16 => zdl::DlSystem::Runtime_t::GPU_FLOAT16; - * DSP, DSP_FIXED8_TF => zdl::DlSystem::Runtime_t::DSP. - * AIP_FIXED_TF, AIP_FIXED8_TF => zdl::DlSystem::Runtime_t::AIP_FIXED_TF. + * "DSP", "DSP_FIXED8_TF", "AIP_FIXED_TF", "AIP_FIXED8_TF". + * Mapping to SNPE Runtime_t definition: + * CPU, CPU_FLOAT32 => zdl::DlSystem::Runtime_t::CPU; + * GPU, GPU_FLOAT32_16_HYBRID => zdl::DlSystem::Runtime_t::GPU; + * GPU_FLOAT16 => zdl::DlSystem::Runtime_t::GPU_FLOAT16; + * DSP, DSP_FIXED8_TF => zdl::DlSystem::Runtime_t::DSP. + * AIP_FIXED_TF, AIP_FIXED8_TF => zdl::DlSystem::Runtime_t::AIP_FIXED_TF. * "priority": execution priority, options: "low", "normal". * "buffer_type": ITensor or user buffers, options: "ITENSOR", user buffer with different types - "TF8", "TF16", "UINT8", "FLOAT". * "ITENSOR" -- default, ITensor which is float only. * "TF8" -- quantized model required, "FLOAT" -- for both quantized or non-quantized model * "enable_init_cache": enable SNPE init caching feature, set to 1 to enabled it. Disabled by default. - * If SNPE is not available (due to a non Snpe enabled build or its dependencies not being installed), this function will fail. * * XNNPACK supported keys: * "intra_op_num_threads": number of thread-pool size to use for XNNPACK execution provider. @@ -4293,8 +4337,8 @@ struct OrtApi { * specific type that is described by the returned ::OrtTypeInfo. * * \param[in] optional_type_info - * \param[out] out A pointer to the ::OrtTypeInfo for what the optional value could be. - * it is owned by OrtOptionalTypeInfo instance. + * \param[out] out A copy of ::OrtTypeInfo for what the optional value could be. + * The user must free this value with ReleaseTypeInfo. * * \snippet{doc} snippets.dox OrtStatus Return Value * @@ -4786,6 +4830,93 @@ struct OrtApi { */ ORT_API2_STATUS(SetEpDynamicOptions, _Inout_ OrtSession* sess, _In_reads_(kv_len) const char* const* keys, _In_reads_(kv_len) const char* const* values, _In_ size_t kv_len); + + /** \brief Release an OrtValueInfo instance if it was not added to an OrtGraph. + * \since Version 1.21. + */ + ORT_CLASS_RELEASE(ValueInfo); + + /** \brief Release an OrtNode if it was not added to an OrtGraph. + * \since Version 1.21. + */ + ORT_CLASS_RELEASE(Node); + + /** \brief Release an OrtGraph. + * \snippet{doc} snippets.dox OrtStatus Return Value + * \since Version 1.21. + */ + ORT_CLASS_RELEASE(Graph); + + /** \brief Release an OrtModel. + * \snippet{doc} snippets.dox OrtStatus Return Value + * \since Version 1.21. + */ + ORT_CLASS_RELEASE(Model); + + /** \brief Get the value name from an OrtValueInfo instance. + * \param[in] value_info The OrtValueInfo instance. + * \snippet{doc} snippets.dox OrtStatus Return Value + * \since Version 1.21. + */ + ORT_API2_STATUS(GetValueInfoName, _In_ const OrtValueInfo* value_info, _Out_ const char** name); + + /** \brief Get the type information from an OrtValueInfo instance. + * \param[in] value_info The OrtValueInfo instance. + * \snippet{doc} snippets.dox OrtStatus Return Value + * \since Version 1.21. + */ + ORT_API2_STATUS(GetValueInfoTypeInfo, _In_ const OrtValueInfo* value_info, _Outptr_ const OrtTypeInfo** type_info); + + /** \brief Get the Model Editor API instance + * + * Get the Model Editor API instance to create a new model or augment an existing model. + * + * \return Model Editor API struct + * + * \since Version 1.21. + */ + const OrtModelEditorApi*(ORT_API_CALL* GetModelEditorApi)(); + + /** \brief Create an OrtValue for a Tensor that uses pre-existing memory. + * + * ORT will take ownership of the memory and free it using the provided deleter when no longer in use. + * + * \param[in] deleter OrtAllocator instance that will be used to free the memory. + * Only the OrtAllocator:Info and OrtAllocator::Release functions are required. + * The OrtMemoryInfo returned by OrtAllocator::Info must match the location of p_data. + * \param[in] p_data Pointer to the memory that will be used by the Tensor. ORT will take ownership of the memory. + * \param[in] p_data_len Length of the memory in bytes. + * \param[in] shape Dimensions of the Tensor. All values should be > 0. + * \param[in] shape_len Number of dimensions in the shape array. + * \param[in] type Data type of the Tensor. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.21. + */ + ORT_API2_STATUS(CreateTensorWithDataAndDeleterAsOrtValue, _In_ OrtAllocator* deleter, + _In_ void* p_data, size_t p_data_len, + _In_ const int64_t* shape, size_t shape_len, + ONNXTensorElementDataType type, + _Outptr_ OrtValue** out); + + /** \brief sets load cancellation flag to abort session loading process. + * + * \param[in] options instance that was passed to the session at creation time. + * \param[in] cancel setting this to true after model loading process was initiated will + * attempt to cancel the loading process. If cancellation is successful, CreateSession() + * CreateSessionFromArray() or any other session creation API that take session options as an + * argument will return an OrtStatus indicating that session loading was canceled at user request, + * error code ORT_MODEL_LOAD_CANCELED. + * The APIs above would not return any valid Session instance. This is the best case effort and the result + * is not guaranteed. The session may have already been created and initialized + * before the cancellation request was issued. + * + * \snippet{doc} snippets.dox OrtStatus + * + */ + ORT_API2_STATUS(SessionOptionsSetLoadCancellationFlag, _Inout_ OrtSessionOptions* options, + _In_ bool cancel); }; /* @@ -4900,6 +5031,400 @@ struct OrtCustomOp { void(ORT_API_CALL* ReleaseAliasMap)(_Frees_ptr_opt_ int* input_index, _Frees_ptr_opt_ int* output_index); }; +/** + * ORT Model Editor API + */ + +/** + * \brief The OrtModelEditorApi struct provides functions to create or edit an ONNX model. + * + * See onnxruntime/test/shared_lib/test_model_editor_api.cc for example usage. + * + * \since Version 1.21. + */ +struct OrtModelEditorApi { + // Model building/editing requires a full build. We return nullptr from GetModelEditorApi if this is a minimal + // build, so it doesn't matter if there are no function pointers in this struct as a user will never get an + // OrtModelEditorApi instance. We do however need a dummy field to avoid empty struct warning. +#if defined(ORT_MINIMAL_BUILD) + const bool not_defined_in_this_build; +#else + /** \brief Create an OrtTypeInfo instance for a Tensor. + * + * Create an OrtTypeInfo instance for a Tensor to use as graph inputs/outputs with the Model Editor API. + * + * User can release `tensor_info` after creating the OrtTypeInfo. + * + * \param[in] tensor_info Tensor type and shape information. + * \param[out] TypeInfo instance for the tensor. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.21. + */ + ORT_API2_STATUS(CreateTensorTypeInfo, _In_ const OrtTensorTypeAndShapeInfo* tensor_info, + _Outptr_ OrtTypeInfo** type_info); + + /** \brief Create an OrtTypeInfo instance for a SparseTensor. + * + * Create an OrtTypeInfo instance for a SparseTensor to use as graph inputs/outputs with the Model Editor API. + * + * User can release `tensor_info` after creating the OrtTypeInfo. + * + * \param[in] tensor_info SparseTensor type and shape information. + * \param[out] TypeInfo instance for the tensor. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.21. + */ + ORT_API2_STATUS(CreateSparseTensorTypeInfo, _In_ const OrtTensorTypeAndShapeInfo* tensor_info, + _Outptr_ OrtTypeInfo** type_info); + + /** \brief Create an OrtTypeInfo instance for a Map. + * + * Create an OrtTypeInfo instance for a Map to use as graph inputs/outputs with the Model Editor API. + * + * User can release `map_value_type` after creating the OrtTypeInfo. + * + * \param[in] map_key_type Key type for the map. + * \param[in] map_value_type Value type for the map. + * \param[out] TypeInfo instance for the map. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.21. + */ + ORT_API2_STATUS(CreateMapTypeInfo, ONNXTensorElementDataType map_key_type, _In_ const OrtTypeInfo* map_value_type, + _Outptr_ OrtTypeInfo** type_info); + + /** \brief Create an OrtTypeInfo instance for a Sequence. + * + * Create an OrtTypeInfo instance for a Sequence to use as graph inputs/outputs with the Model Editor API. + * + * User can release `sequence_type` after creating the OrtTypeInfo. + * + * \param[in] sequence_type Sequence type and shape information. + * \param[out] TypeInfo instance for the sequence. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.21. + */ + ORT_API2_STATUS(CreateSequenceTypeInfo, _In_ const OrtTypeInfo* sequence_type, _Outptr_ OrtTypeInfo** type_info); + + /** \brief Create an OrtTypeInfo instance for an Optional. + * + * Create an OrtTypeInfo instance for an Optional to use as graph inputs/outputs with the Model Editor API. + * + * User can release `contained_type` after creating the OrtTypeInfo. + * + * \param[in] tensor_info Tensor type and shape information. + * \param[out] TypeInfo instance for the tensor. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.21. + */ + ORT_API2_STATUS(CreateOptionalTypeInfo, _In_ const OrtTypeInfo* contained_type, _Outptr_ OrtTypeInfo** type_info); + + /** \brief Create an OrtValueInfo for use as an OrtGraph input or output. + * + * \param[in] name The name of the input or output. + * \param[in] type_info The type information for the input or output. The provided value is copied. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.21. + */ + ORT_API2_STATUS(CreateValueInfo, _In_ const char* name, _In_ const OrtTypeInfo* type_info, + _Outptr_ OrtValueInfo** value_info); + + /** \brief Create an OrtNode to add to an OrtGraph. + * + * Create an OrtNode. + * + * Create attributes with CreateOpAttr. OrtOpAttr instances are copied. + * + * \param[in] operator_name The name of the operator. + * \param[in] domain_name The domain of the operator. Use an empty string for ONNX operators. + * \param[in] node_name The name of the node. + * \param[in] input_names The names of the inputs. + * \param[in] input_names_len The number of input names. + * \param[in] output_names The names of the outputs. + * \param[in] output_names_len The number of output names. + * \param[in] attributes The optional attributes of the node. + * \param[in] attribs_len The number of attributes. May be zero. + * \param[out] node The OrtNode instance. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.21. + */ + ORT_API2_STATUS(CreateNode, _In_ const char* operator_name, _In_ const char* domain_name, _In_ const char* node_name, + _In_reads_(input_names_len) const char* const* input_names, size_t input_names_len, + _In_reads_(output_names_len) const char* const* output_names, size_t output_names_len, + _In_reads_(attribs_len) _In_opt_ OrtOpAttr** attributes, _In_ size_t attribs_len, + _Outptr_ OrtNode** node); + + /** \brief Create an OrtGraph + * \snippet{doc} snippets.dox OrtStatus Return Value + * \since Version 1.21. + */ + ORT_API2_STATUS(CreateGraph, _Outptr_ OrtGraph** graph); + + /** \brief Set the inputs for the OrtGraph. + * + * Set the graph inputs. This will replace any existing inputs with the new values. + * The OrtGraph takes ownership of the OrtValueInfo instances and you should NOT call ReleaseOrtValueInfo. + * + * \param[in] graph The OrtGraph instance to update. + * \param[in] inputs The input OrtValueInfo instances. + * \param[in] inputs_len The number of input OrtValueInfo instances. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.21. + */ + ORT_API2_STATUS(SetGraphInputs, _Inout_ OrtGraph* graph, + _In_reads_(inputs_len) _In_ OrtValueInfo** inputs, _In_ size_t inputs_len); + + /** \brief Set the outputs for the OrtGraph. + * + * Set the graph outputs. This will replace any existing outputs with the new values. + * The OrtGraph takes ownership of the OrtValueInfo instances provided and you should NOT call ReleaseOrtValueInfo. + * + * \param[in] graph The OrtGraph instance to update. + * \param[in] outputs The output OrtValueInfo instances. + * \param[in] outputs_len The number of output OrtValueInfo instances. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.21. + */ + ORT_API2_STATUS(SetGraphOutputs, _Inout_ OrtGraph* graph, + _In_reads_(outputs_len) _In_ OrtValueInfo** outputs, _In_ size_t outputs_len); + + /** \brief Add an initializer to the OrtGraph + * + * ORT will take ownership of the OrtValue and you should NOT call ReleaseOrtValue. + * + * Two options: + * + * Allocated memory: + * Use CreateTensorAsOrtValue (allocates memory) and populate the tensor with the data. + * Set `data_is_external` to false. + * + * Pre-existing memory: + * Use CreateTensorWithDataAsOrtValue or CreateTensorWithDataAndDeleterAsOrtValue to create an OrtValue + * with a tensor that contains a pointer to the existing data. + * Set `data_is_external` to true. + * + * The pointer must remain valid for the duration of the inference session. + * If using CreateTensorWithDataAsOrtValue you are responsible for freeing the memory after the inference session + * is released. + * If using CreateTensorWithDataAndDeleterAsOrtValue, ORT will free the memory using the provided deleter as + * soon as the OrtValue is no longer in use. + * + * NOTE: A tensor containing pre-existing memory MUST have 128 bytes of data or more. + * For smaller tensors use CreateTensorAsOrtValue. + * + * ONNX shape inferencing does not support external data. An initializer involved in shape inferencing is + * typically small (a single value or limited by the rank of a tensor) and uses less than 128 bytes of + * memory, so this limit acts as a simple catch-all rule to avoid issues. + * e.g. Reshape's `shape`, Clip's `min` and `max`, various ops `axes`. + * + * \param[in] graph The OrtGraph instance to update. + * \param[in] name The value name for the initializer. + * \param[in] tensor The OrtValue instance containing the tensor data. + * \param[in] data_is_external Set to true if the data is external and should not be copied. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.21. + */ + ORT_API2_STATUS(AddInitializerToGraph, _Inout_ OrtGraph* graph, _In_ const char* name, _In_ OrtValue* tensor, + bool data_is_external); + + /** \brief Add an OrtNode to an OrtGraph + * + * Add the node to the graph. The OrtGraph will take ownership of OrtNode and you should NOT call ReleaseOrtNode. + * + * \param[in] graph The OrtGraph instance to update. + * \param[in] node The OrtNode instance to add to the graph. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.21. + */ + ORT_API2_STATUS(AddNodeToGraph, _Inout_ OrtGraph* graph, _In_ OrtNode* node); + + /** \brief Create an OrtModel. + * + * Create an OrtModel. + * + * This can be used to build a new model, or to augment an existing model. + * + * \param[in] domain_names The domain names for the model. + * If augmenting an existing model add additional domains if needed. + * \param[in] opset_versions The opset versions for the model. + * If augmenting an existing model add additional opset versions if needed. + * \param[in] opset_entries_len The number of domain_names and opset_versions entries. + * Domain and opset entries should be 1:1 + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.21. + */ + ORT_API2_STATUS(CreateModel, + _In_reads_(opset_entries_len) const char* const* domain_names, + _In_reads_(opset_entries_len) const int* opset_versions, + size_t opset_entries_len, + _Outptr_ OrtModel** model); + + /** \brief Add an OrtGraph to an OrtModel. + * + * Add the graph to a model. This should be called once when creating a new model. + * + * The OrtModel takes ownership of the OrtGraph and you should NOT call ReleaseOrtGraph. + * + * \param[in] model The OrtModel instance to update. + * \param[in] graph The OrtGraph instance to add to the model. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.21. + */ + ORT_API2_STATUS(AddGraphToModel, _Inout_ OrtModel* model, _In_ OrtGraph* graph); + + /** \brief Create an OrtSession using the OrtModel. + * + * Create an inference session using the OrtModel instance. + * The OrtModel should have been populated with an OrtGraph containing nodes and initializers, and SetGraphInputs + * and SetGraphOutputs must have been called. + * This will validate the model, run optimizers, and prepare the session for inferencing. + * + * ReleaseOrtModel must be called to free the OrtModel after session creation. + * + * \param[in] env The OrtEnv instance. + * \param[in] model The OrtModel instance. + * \param[in] options The OrtSessionOptions instance. + * \param[out] out The OrtSession instance. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.21. + */ + ORT_API2_STATUS(CreateSessionFromModel, _In_ const OrtEnv* env, _In_ const OrtModel* model, + _In_ const OrtSessionOptions* options, _Outptr_ OrtSession** out); + + /** \brief Create an OrtSession to augment an existing model. + * + * Create an OrtSession with an existing model that will be augmented with additional nodes and initializers. + * Nodes can be added before or after the existing nodes in the model. ONNX Runtime will connect the nodes when the + * model is finalized. + * + * To add nodes and initializers to the existing model, first create an OrtModel using CreateModel. + * Add nodes and initializers to the OrtModel using AddNodeToGraph and AddInitializerToGraph. + * Graph inputs/outputs should be updated with SetGraphInputs and SetGraphOutputs as needed to reflect changes made + * by the new nodes. The list of graph inputs/outputs should be for the overall model and not just the new nodes. + * + * Add the new information from the OrtModel to the original model using ApplyModelToSession, and prepare the + * session for inferencing by calling FinalizeModelEditorSession. + * + * \param{in} env The OrtEnv instance. + * \param{in} model_path The path to the existing ONNX model to augment. + * \param{in} options The OrtSessionOptions instance. + * \param{out} out The created OrtSession instance. + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.21. + */ + ORT_API2_STATUS(CreateModelEditorSession, _In_ const OrtEnv* env, _In_ const ORTCHAR_T* model_path, + _In_ const OrtSessionOptions* options, + _Outptr_ OrtSession** out); + + /** \brief Create an OrtSession to augment an existing model. + * + * Create an OrtSession with an existing model that will be augmented with additional nodes and initializers. + * Nodes can be added before or after the existing nodes in the model. ONNX Runtime will connect the nodes when the + * model is finalized. + * + * To add nodes and initializers to the existing model, first create an OrtModel using CreateModel. + * Add nodes and initializers to the OrtModel using AddNodeToGraph and AddInitializerToGraph. + * Graph inputs/outputs should be updated with SetGraphInputs and SetGraphOutputs as needed to reflect changes made + * by the new nodes. The list of graph inputs/outputs should be for the overall model and not just the new nodes. + * + * Add the new information from the OrtModel to the original model using ApplyModelToSession, and prepare the + * session for inferencing by calling FinalizeModelEditorSession. + * + * \param{in} env The OrtEnv instance. + * \param{in} model_data The model data for the existing model to augment. + * \param{in} model_data_length The length of the model data. + * \param{in} options The OrtSessionOptions instance. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.21. + */ + ORT_API2_STATUS(CreateModelEditorSessionFromArray, _In_ const OrtEnv* env, + _In_ const void* model_data, size_t model_data_length, + _In_ const OrtSessionOptions* options, + _Outptr_ OrtSession** out); + + /** \brief Query the session for the opset version of a domain. + * + * When using the Model Editor API to augment a model, any new nodes must conform to the opset version of the + * original model. To do that the user must be able to discover that opset version. + * + * \param[in] session OrtSession to query + * \param[in] domain Domain to query. The ONNX domain is an empty string. + * \param[out] opset The opset version of the domain. + * + * \snippet{doc} snippets.dox OrtStatus Return Value. Returns an error if the domain is not used in the model. + * + * \since Version 1.21. + */ + ORT_API2_STATUS(SessionGetOpsetForDomain, _In_ const OrtSession* session, _In_ const char* domain, _Out_ int* opset); + + /** \brief Apply changes to augment the ONNX model in a session created using CreateModelEditorSession[FromArray] + * + * Adds new nodes and updates graph inputs/outputs using `model` to augment the original ONNX model in the session. + * All changes will be validated. + * Call FinalizeModelEditorSession to prepare the session for inferencing. + * + * Existing input/outputs will only be updated if the OrtGraph inputs/outputs are set in the OrtModel. + * i.e. you don't need to call SetGraphInputs/SetGraphOutputs if they are unchanged. + * + * ReleaseOrtModel must be called to free the OrtModel after it is applied to the session. + * + * \param[in] session OrtSession to update. Session must have been created using CreateModelEditorSession[FromArray]. + * \param[in] model OrtModel containing new nodes, new initializers, and updated graph input and/or output info. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.21. + */ + ORT_API2_STATUS(ApplyModelToModelEditorSession, _Inout_ OrtSession* session, _In_ OrtModel* model); + + /** \brief Finalize the Model Editor session that was created using CreateModelEditorSession[FromArray]. + * + * Finalize the Model Editor session that augmented an ONNX model by adding new nodes. + * This will run optimizers and prepare the session for inferencing. + * + * \param[in] session OrtSession to finalize. Session must have been created using CreateModelEditorSession[FromArray]. + * \param[in] options OrtSessionOptions to use for the session. + * \param[in] Optional prepacked_weights_container OrtPrepackedWeightsContainer to use for the session. + Set to nullptr if not used. + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.21. + */ + ORT_API2_STATUS(FinalizeModelEditorSession, _Inout_ OrtSession* session, _In_ const OrtSessionOptions* options, + _In_opt_ OrtPrepackedWeightsContainer* prepacked_weights_container); +#endif // !defined(ORT_MINIMAL_BUILD) +}; + /* * This is the old way to add the CUDA provider to the session, please use SessionOptionsAppendExecutionProvider_CUDA above to access the latest functionality * This function always exists, but will only succeed if Onnxruntime was built with CUDA support and the CUDA provider shared library exists diff --git a/include/onnxruntime/core/session/onnxruntime_cxx_api.h b/include/onnxruntime/core/session/onnxruntime_cxx_api.h index 123ef98901003..ce7dc1c45b05e 100644 --- a/include/onnxruntime/core/session/onnxruntime_cxx_api.h +++ b/include/onnxruntime/core/session/onnxruntime_cxx_api.h @@ -26,16 +26,17 @@ #include "onnxruntime_c_api.h" #include "onnxruntime_float16.h" +#include #include #include -#include #include #include #include -#include +#include #include #include -#include +#include +#include #ifdef ORT_NO_EXCEPTIONS #include @@ -120,7 +121,7 @@ const OrtApi* Global::api_ = OrtGetApiBase()->GetApi(ORT_API_VERSION); #endif #endif -/// This returns a reference to the OrtApi interface in use +/// This returns a reference to the ORT C API. inline const OrtApi& GetApi() noexcept { return *Global::api_; } /// @@ -143,6 +144,20 @@ std::string GetBuildInfoString(); /// vector of strings std::vector GetAvailableProviders(); +/// +/// This returns a reference to the ORT C Model Editor API. Used if building or augmenting a model at runtime. +/// +/// ORT C Model Editor API reference +inline const OrtModelEditorApi& GetModelEditorApi() { + auto* api = GetApi().GetModelEditorApi(); + if (api == nullptr) { + // minimal build + ORT_CXX_API_THROW("Model Editor API is not available in this build", ORT_FAIL); + } + + return *api; +} + /** \brief IEEE 754 half-precision floating point data type * * \details This struct is used for converting float to float16 and back @@ -523,6 +538,10 @@ ORT_DEFINE_RELEASE(Status); ORT_DEFINE_RELEASE(OpAttr); ORT_DEFINE_RELEASE(Op); ORT_DEFINE_RELEASE(KernelInfo); +ORT_DEFINE_RELEASE(ValueInfo); +ORT_DEFINE_RELEASE(Node); +ORT_DEFINE_RELEASE(Graph); +ORT_DEFINE_RELEASE(Model); #undef ORT_DEFINE_RELEASE @@ -559,7 +578,9 @@ struct Base { constexpr Base() = default; constexpr explicit Base(contained_type* p) noexcept : p_{p} {} - ~Base() { OrtRelease(p_); } + ~Base() { + OrtRelease(p_); + } Base(const Base&) = delete; Base& operator=(const Base&) = delete; @@ -635,9 +656,13 @@ struct AllocatedFree { struct AllocatorWithDefaultOptions; struct Env; +struct Graph; +struct Model; +struct Node; +struct ModelMetadata; struct TypeInfo; struct Value; -struct ModelMetadata; +struct ValueInfo; /** \brief unique_ptr typedef used to own strings allocated by OrtAllocators * and release them at the end of the scope. The lifespan of the given allocator @@ -903,6 +928,8 @@ struct SessionOptionsImpl : ConstSessionOptionsImpl { SessionOptionsImpl& SetExecutionMode(ExecutionMode execution_mode); ///< Wraps OrtApi::SetSessionExecutionMode + SessionOptionsImpl& SetLoadCancellationFlag(bool value); ///< Wraps OrtApi::SessionOptionsSetLoadCancellationFlag + SessionOptionsImpl& SetLogId(const char* logid); ///< Wraps OrtApi::SetSessionLogId SessionOptionsImpl& SetLogSeverityLevel(int level); ///< Wraps OrtApi::SetSessionLogSeverityLevel @@ -1051,6 +1078,10 @@ struct ConstSessionImpl : Base { size_t GetOutputCount() const; ///< Returns the number of model outputs size_t GetOverridableInitializerCount() const; ///< Returns the number of inputs that have defaults that can be overridden + std::vector GetInputNames() const; + std::vector GetOutputNames() const; + std::vector GetOverridableInitializerNames() const; + /** \brief Returns a copy of input name at the specified index. * * \param index must less than the value returned by GetInputCount() @@ -1084,6 +1115,12 @@ struct ConstSessionImpl : Base { TypeInfo GetInputTypeInfo(size_t index) const; ///< Wraps OrtApi::SessionGetInputTypeInfo TypeInfo GetOutputTypeInfo(size_t index) const; ///< Wraps OrtApi::SessionGetOutputTypeInfo TypeInfo GetOverridableInitializerTypeInfo(size_t index) const; ///< Wraps OrtApi::SessionGetOverridableInitializerTypeInfo + + int GetOpset(const std::string& domain) const; ///< Wraps OrtApi::SessionGetOpsetForDomain + + // Will move before checkin if that's the case. + std::vector GetInputs() const; + std::vector GetOutputs() const; }; template @@ -1161,6 +1198,9 @@ struct SessionImpl : ConstSessionImpl { * \param[in] kv_len Number of elements in the keys and values arrays */ void SetEpDynamicOptions(const char* const* keys, const char* const* values, size_t kv_len); + + void FinalizeModelEditorSession(const Model& model, const SessionOptions& options, + OrtPrepackedWeightsContainer* prepacked_weights_container = nullptr); }; } // namespace detail @@ -1172,13 +1212,34 @@ using UnownedSession = detail::SessionImpl>; * */ struct Session : detail::SessionImpl { - explicit Session(std::nullptr_t) {} ///< Create an empty Session object, must be assigned a valid one to be used - Session(const Env& env, const ORTCHAR_T* model_path, const SessionOptions& options); ///< Wraps OrtApi::CreateSession + /// Create an empty Session object, must be assigned a valid one to be used. Wraps OrtApi::CreateSession + explicit Session(std::nullptr_t) {} + explicit Session(OrtSession* p) : SessionImpl{p} {} ///< C API Interop + + Session(const Env& env, const ORTCHAR_T* model_path, const SessionOptions& options); + + /// Wraps OrtApi::CreateSessionWithPrepackedWeightsContainer Session(const Env& env, const ORTCHAR_T* model_path, const SessionOptions& options, - OrtPrepackedWeightsContainer* prepacked_weights_container); ///< Wraps OrtApi::CreateSessionWithPrepackedWeightsContainer - Session(const Env& env, const void* model_data, size_t model_data_length, const SessionOptions& options); ///< Wraps OrtApi::CreateSessionFromArray + OrtPrepackedWeightsContainer* prepacked_weights_container); + + /// Wraps OrtApi::CreateSessionFromArray + Session(const Env& env, const void* model_data, size_t model_data_length, const SessionOptions& options); + + /// Wraps OrtApi::CreateSessionFromArrayWithPrepackedWeightsContainer Session(const Env& env, const void* model_data, size_t model_data_length, const SessionOptions& options, - OrtPrepackedWeightsContainer* prepacked_weights_container); ///< Wraps OrtApi::CreateSessionFromArrayWithPrepackedWeightsContainer + OrtPrepackedWeightsContainer* prepacked_weights_container); + +#if !defined(ORT_MINIMAL_BUILD) + /// Wraps OrtModelEditorApi::CreateSessionFromModel + Session(const Env& env, const Model& model, const SessionOptions& options); + + /// Wraps OrtModelEditorApi::CreateModelEditorSession + static Session CreateModelEditorSession(const Env& env, const ORTCHAR_T* model_path, const SessionOptions& options); + + /// Wraps OrtModelEditorApi::CreateModelEditorSession + static Session CreateModelEditorSession(const Env& env, const void* model_data, size_t model_data_length, + const SessionOptions& options); +#endif // !defined(ORT_MINIMAL_BUILD) ConstSession GetConst() const { return ConstSession{this->p_}; } UnownedSession GetUnowned() const { return UnownedSession{this->p_}; } @@ -1210,7 +1271,7 @@ using ConstMemoryInfo = detail::MemoryInfoImpl { static MemoryInfo CreateCpu(OrtAllocatorType type, OrtMemType mem_type1); explicit MemoryInfo(std::nullptr_t) {} ///< No instance is created - explicit MemoryInfo(OrtMemoryInfo* p) : MemoryInfoImpl{p} {} ///< Take ownership of a pointer created by C Api + explicit MemoryInfo(OrtMemoryInfo* p) : MemoryInfoImpl{p} {} ///< Take ownership of a pointer created by C API MemoryInfo(const char* name, OrtAllocatorType type, int id, OrtMemType mem_type); ConstMemoryInfo GetConst() const { return ConstMemoryInfo{this->p_}; } }; @@ -1233,6 +1294,7 @@ struct TensorTypeAndShapeInfoImpl : Base { [[deprecated("use GetShape()")]] void GetDimensions(int64_t* values, size_t values_count) const; ///< Wraps OrtApi::GetDimensions void GetSymbolicDimensions(const char** values, size_t values_count) const; ///< Wraps OrtApi::GetSymbolicDimensions + std::vector GetSymbolicDimensions() const; std::vector GetShape() const; ///< Uses GetDimensionsCount & GetDimensions to return a std::vector of the shape }; @@ -1248,8 +1310,18 @@ struct TensorTypeAndShapeInfo : detail::TensorTypeAndShapeInfoImpl; using Base::Base; - explicit TensorTypeAndShapeInfo(std::nullptr_t) {} ///< Create an empty TensorTypeAndShapeInfo object, must be assigned a valid one to be used - explicit TensorTypeAndShapeInfo(OrtTensorTypeAndShapeInfo* p) : TensorTypeAndShapeInfoImpl{p} {} ///< Used for interop with the C API + /// Create an empty TensorTypeAndShapeInfo object, must be assigned a valid one to be used + explicit TensorTypeAndShapeInfo(std::nullptr_t) {} + /// Used for interop with the C API + explicit TensorTypeAndShapeInfo(OrtTensorTypeAndShapeInfo* p) : TensorTypeAndShapeInfoImpl{p} {} + + // Create a TensorTypeAndShapeInfo object with the specified element type and dimensions + // symbolic_dims are optional, but should be 1:1 with dims. + // The value in symbolic_dims will be used for all entries in dims that are -1. + explicit TensorTypeAndShapeInfo(ONNXTensorElementDataType element_type, + const std::vector& dims, + const std::vector* symbolic_dims = nullptr); + ConstTensorTypeAndShapeInfo GetConst() const { return ConstTensorTypeAndShapeInfo{this->p_}; } }; @@ -1344,9 +1416,18 @@ struct TypeInfo : detail::TypeInfoImpl { using Base = detail::TypeInfoImpl; using Base::Base; - explicit TypeInfo(std::nullptr_t) {} ///< Create an empty TypeInfo object, must be assigned a valid one to be used + /// Create an empty TypeInfo object, must be assigned a valid one to be used + explicit TypeInfo(std::nullptr_t) {} explicit TypeInfo(OrtTypeInfo* p) : TypeInfoImpl{p} {} ///< C API Interop +#if !defined(ORT_MINIMAL_BUILD) + static TypeInfo CreateTensorInfo(ConstTensorTypeAndShapeInfo tensor_info); + static TypeInfo CreateSparseTensorInfo(ConstTensorTypeAndShapeInfo sparse_tensor_info); + static TypeInfo CreateSequenceTypeInfo(ConstTypeInfo sequence_type); + static TypeInfo CreateMapTypeInfo(ONNXTensorElementDataType key_type, ConstTypeInfo value_type); + static TypeInfo CreateOptionalTypeInfo(ConstTypeInfo contained_type); +#endif // !defined(ORT_MINIMAL_BUILD) + ConstTypeInfo GetConst() const { return ConstTypeInfo{this->p_}; } }; @@ -1701,7 +1782,8 @@ struct Value : detail::ValueImpl { * \param shape_len The number of tensor shape dimensions. */ template - static Value CreateTensor(const OrtMemoryInfo* info, T* p_data, size_t p_data_element_count, const int64_t* shape, size_t shape_len); + static Value CreateTensor(const OrtMemoryInfo* info, T* p_data, size_t p_data_element_count, + const int64_t* shape, size_t shape_len); /** \brief Creates a tensor with a user supplied buffer. Wraps OrtApi::CreateTensorWithDataAsOrtValue. * @@ -1712,11 +1794,25 @@ struct Value : detail::ValueImpl { * \param shape_len The number of tensor shape dimensions. * \param type The data type. */ - static Value CreateTensor(const OrtMemoryInfo* info, void* p_data, size_t p_data_byte_count, const int64_t* shape, size_t shape_len, + static Value CreateTensor(const OrtMemoryInfo* info, void* p_data, size_t p_data_byte_count, + const int64_t* shape, size_t shape_len, + ONNXTensorElementDataType type); + + /** \brief Creates a tensor with a user supplied buffer. Wraps OrtApi::CreateTensorWithDataAndDeleterAsOrtValue. + * + * \param deleter OrtAllocator that will be used to free the buffer when no longer required. + * \param p_data Pointer to the data buffer. + * \param p_data_byte_count The number of bytes in the data buffer. + * \param shape Pointer to the tensor shape dimensions. + * \param shape_len The number of tensor shape dimensions. + * \param type The data type. + */ + static Value CreateTensor(OrtAllocator* deleter, void* p_data, size_t p_data_byte_count, + const int64_t* shape, size_t shape_len, ONNXTensorElementDataType type); /** \brief Creates an OrtValue with a tensor using a supplied OrtAllocator. Wraps OrtApi::CreateTensorAsOrtValue. - * This overload will allocate the buffer for the tensor according to the supplied shape and data type. + * This overload will allocate the buffer for the tensor according to the supplied shape and data type. * The allocated buffer will be owned by the returned OrtValue and will be freed when the OrtValue is released. * The input data would need to be copied into the allocated buffer. * This API is not suitable for strings. @@ -1740,7 +1836,8 @@ struct Value : detail::ValueImpl { * \param shape_len The number of tensor shape dimensions. * \param type The data type. */ - static Value CreateTensor(OrtAllocator* allocator, const int64_t* shape, size_t shape_len, ONNXTensorElementDataType type); + static Value CreateTensor(OrtAllocator* allocator, const int64_t* shape, size_t shape_len, + ONNXTensorElementDataType type); /** \brief Creates an OrtValue with a Map Onnx type representation. * The API would ref-count the supplied OrtValues and they will be released @@ -2437,6 +2534,9 @@ struct CustomOpBase : OrtCustomOp { return std::vector{}; } + // Ort::CustomOpBase derived class should provide the following static method with the type/shape inferencing + // implementation if needed: + // static OrtStatusPtr InferOutputShape(Ort::ShapeInferContext& context) template decltype(&C::InferOutputShape) SetShapeInferFn(decltype(&C::InferOutputShape)) { OrtCustomOp::InferOutputShapeFn = [](const OrtCustomOp*, OrtShapeInferContext* ort_ctx) -> OrtStatusPtr { @@ -2459,6 +2559,129 @@ struct CustomOpBase : OrtCustomOp { int end_ver_ = MAX_CUSTOM_OP_END_VER; }; -} // namespace Ort +namespace detail { +template +struct ValueInfoImpl : Ort::detail::Base { + using B = Ort::detail::Base; + using B::B; + + std::string Name() const; + ConstTypeInfo TypeInfo() const; +}; +} // namespace detail + +// Const object holder that does not own the underlying object +using ConstValueInfo = detail::ValueInfoImpl>; + +/** \brief Wrapper around ::OrtValueInfo + * + */ +struct ValueInfo : detail::ValueInfoImpl { + explicit ValueInfo(std::nullptr_t) {} ///< No instance is created + /// Take ownership of a pointer created by C API + explicit ValueInfo(OrtValueInfo* p) : ValueInfoImpl{p} {} + + // Create ValueInfo for a tensor + explicit ValueInfo(const std::string& name, const ConstTypeInfo& type_info); + + ConstValueInfo GetConst() const { return ConstValueInfo{this->p_}; } +}; + +namespace detail { +template +struct NodeImpl : Ort::detail::Base { + using B = Ort::detail::Base; + using B::B; +}; +} // namespace detail + +/** \brief Wrapper around ::OrtNode + * + */ +struct Node : detail::NodeImpl { + explicit Node(std::nullptr_t) {} ///< No instance is created + explicit Node(OrtNode* p) : NodeImpl{p} {} ///< Take ownership of a pointer created by C API + +#if !defined(ORT_MINIMAL_BUILD) + Node(const std::string& operator_name, const std::string& operator_domain, + const std::string& node_name, + const std::vector& input_names, + const std::vector& output_names); + /// + /// Wraps CreateNode. Node takes ownership of attributes on success and updates the OpAttr in `attributes` to do so. + /// + Node(const std::string& operator_name, const std::string& operator_domain, + const std::string& node_name, + const std::vector& input_names, + const std::vector& output_names, + std::vector& attributes); + + private: + static void Init(const std::string& operator_name, const std::string& operator_domain, + const std::string& node_name, + const std::vector& input_names, + const std::vector& output_names, + std::vector& attributes, + OrtNode*& node); +#endif // !defined(ORT_MINIMAL_BUILD) +}; + +namespace detail { +template +struct GraphImpl : Ort::detail::Base { + using B = Ort::detail::Base; + using B::B; + +#if !defined(ORT_MINIMAL_BUILD) + void SetInputs(std::vector& inputs); + void SetOutputs(std::vector& outputs); + void AddInitializer(const std::string& name, Value& initializer, bool data_is_external); // Graph takes ownership of Value + void AddNode(Node& node); // Graph takes ownership of Node +#endif // !defined(ORT_MINIMAL_BUILD) +}; +} // namespace detail + +/** \brief Wrapper around ::OrtGraph + * + */ +struct Graph : detail::GraphImpl { + explicit Graph(std::nullptr_t) {} ///< No instance is created + explicit Graph(OrtGraph* p) : GraphImpl{p} {} ///< Take ownership of a pointer created by C API +#if !defined(ORT_MINIMAL_BUILD) + Graph(); +#endif +}; + +namespace detail { +template +struct ModelImpl : Ort::detail::Base { + using B = Ort::detail::Base; + using B::B; + +#if !defined(ORT_MINIMAL_BUILD) + void AddGraph(Graph& graph); +#endif +}; +} // namespace detail + +// Const object holder that does not own the underlying object +using ConstModel = detail::ModelImpl>; + +/** \brief Wrapper around ::OrtModel + * + */ +struct Model : detail::ModelImpl { + using DomainOpsetPair = std::pair; + + explicit Model(std::nullptr_t) {} ///< No instance is created + explicit Model(OrtModel* p) : ModelImpl{p} {} ///< Take ownership of a pointer created by C API + +#if !defined(ORT_MINIMAL_BUILD) + explicit Model(const std::vector& opsets); +#endif + + ConstModel GetConst() const { return ConstModel{this->p_}; } +}; +} // namespace Ort #include "onnxruntime_cxx_inline.h" diff --git a/include/onnxruntime/core/session/onnxruntime_cxx_inline.h b/include/onnxruntime/core/session/onnxruntime_cxx_inline.h index 3aeb9412f350e..524e3ecc92936 100644 --- a/include/onnxruntime/core/session/onnxruntime_cxx_inline.h +++ b/include/onnxruntime/core/session/onnxruntime_cxx_inline.h @@ -10,7 +10,9 @@ #include #include #include +#include #include +#include // Convert OrtStatus to Ort::Status and return // instead of throwing @@ -745,6 +747,12 @@ inline SessionOptionsImpl& SessionOptionsImpl::SetExecutionMode(ExecutionM return *this; } +template +inline SessionOptionsImpl& SessionOptionsImpl::SetLoadCancellationFlag(bool value) { + ThrowOnError(GetApi().SessionOptionsSetLoadCancellationFlag(this->p_, value)); + return *this; +} + template inline SessionOptionsImpl& SessionOptionsImpl::SetLogId(const char* logid) { ThrowOnError(GetApi().SetSessionLogId(this->p_, logid)); @@ -995,6 +1003,59 @@ inline size_t ConstSessionImpl::GetOverridableInitializerCount() const { return out; } +template +inline std::vector ConstSessionImpl::GetInputNames() const { + AllocatorWithDefaultOptions allocator; + + auto num_inputs = GetInputCount(); + std::vector input_names; + input_names.reserve(num_inputs); + + for (size_t i = 0; i < num_inputs; ++i) { + char* name = nullptr; + ThrowOnError(GetApi().SessionGetInputName(this->p_, i, allocator, &name)); + input_names.push_back(name); + allocator.Free(name); + } + + return input_names; +} + +template +inline std::vector ConstSessionImpl::GetOutputNames() const { + AllocatorWithDefaultOptions allocator; + + auto num_inputs = GetOutputCount(); + std::vector output_names; + output_names.reserve(num_inputs); + + for (size_t i = 0; i < num_inputs; ++i) { + char* name = nullptr; + ThrowOnError(GetApi().SessionGetOutputName(this->p_, i, allocator, &name)); + output_names.push_back(name); + allocator.Free(name); + } + + return output_names; +} + +template +inline std::vector ConstSessionImpl::GetOverridableInitializerNames() const { + AllocatorWithDefaultOptions allocator; + + auto num_initializers = GetOverridableInitializerCount(); + std::vector initializer_names; + initializer_names.reserve(num_initializers); + + for (size_t i = 0; i < num_initializers; ++i) { + char* name = nullptr; + ThrowOnError(GetApi().SessionGetOverridableInitializerName(this->p_, i, allocator, &name)); + initializer_names.push_back(name); + } + + return initializer_names; +} + template inline AllocatedStringPtr ConstSessionImpl::GetInputNameAllocated(size_t index, OrtAllocator* allocator) const { char* out; @@ -1051,6 +1112,45 @@ inline TypeInfo ConstSessionImpl::GetOverridableInitializerTypeInfo(size_t in return TypeInfo{out}; } +#if !defined(ORT_MINIMAL_BUILD) +template +inline int ConstSessionImpl::GetOpset(const std::string& domain) const { + int opset; + ThrowOnError(GetModelEditorApi().SessionGetOpsetForDomain(this->p_, domain.c_str(), &opset)); + return opset; +} +#endif // !defined(ORT_MINIMAL_BUILD) + +template +std::vector ConstSessionImpl::GetInputs() const { + const std::vector input_names = GetInputNames(); + + std::vector inputs; + inputs.reserve(input_names.size()); + + for (size_t i = 0; i < input_names.size(); ++i) { + auto type_info = GetInputTypeInfo(i); + inputs.emplace_back(ValueInfo{input_names[i], type_info.GetConst()}); + } + + return inputs; +} + +template +std::vector ConstSessionImpl::GetOutputs() const { + const std::vector output_names = GetOutputNames(); + + std::vector outputs; + outputs.reserve(output_names.size()); + + for (size_t i = 0; i < output_names.size(); ++i) { + auto type_info = GetOutputTypeInfo(i); + outputs.emplace_back(ValueInfo{output_names[i], type_info.GetConst()}); + } + + return outputs; +} + template inline std::vector SessionImpl::Run(const RunOptions& run_options, const char* const* input_names, const Value* input_values, size_t input_count, const char* const* output_names, size_t output_count) { @@ -1098,6 +1198,15 @@ inline void SessionImpl::SetEpDynamicOptions(const char* const* keys, const c ThrowOnError(GetApi().SetEpDynamicOptions(this->p_, keys, values, kv_len)); } +#if !defined(ORT_MINIMAL_BUILD) +template +inline void SessionImpl::FinalizeModelEditorSession(const Model& model, const SessionOptions& options, + OrtPrepackedWeightsContainer* prepacked_weights_container) { + ThrowOnError(GetModelEditorApi().ApplyModelToModelEditorSession(this->p_, model)); + ThrowOnError(GetModelEditorApi().FinalizeModelEditorSession(this->p_, options, prepacked_weights_container)); +} +#endif // #if !defined(ORT_MINIMAL_BUILD) + } // namespace detail inline SessionOptions::SessionOptions() { @@ -1144,6 +1253,32 @@ inline Session::Session(const Env& env, const void* model_data, size_t model_dat prepacked_weights_container, &this->p_)); } +#if !defined(ORT_MINIMAL_BUILD) +inline Session::Session(const Env& env, const Model& model, const SessionOptions& options) { + ThrowOnError(GetModelEditorApi().CreateSessionFromModel(env, model.GetConst(), options, &this->p_)); +} + +// static +inline Session Session::CreateModelEditorSession(const Env& env, const ORTCHAR_T* model_path, + const SessionOptions& options) { + OrtSession* session = nullptr; + ThrowOnError(GetModelEditorApi().CreateModelEditorSession(env, model_path, options, &session)); + return Session(session); +} + +// static +inline Session Session::CreateModelEditorSession(const Env& env, const void* model_data, size_t model_data_length, + const SessionOptions& options) { + OrtSession* session = nullptr; + ThrowOnError(GetModelEditorApi().CreateModelEditorSessionFromArray(env, model_data, model_data_length, options, + &session)); + return Session(session); +} + +void FinalizeModelEditorSession(const Model& model, const SessionOptions& options, + OrtPrepackedWeightsContainer* prepacked_weights_container); +#endif // #if !defined(ORT_MINIMAL_BUILD) + inline AllocatedStringPtr ModelMetadata::GetProducerNameAllocated(OrtAllocator* allocator) const { char* out; ThrowOnError(GetApi().ModelMetadataGetProducerName(p_, allocator, &out)); @@ -1211,6 +1346,59 @@ inline int64_t ModelMetadata::GetVersion() const { return out; } +inline TensorTypeAndShapeInfo::TensorTypeAndShapeInfo(ONNXTensorElementDataType element_type, + const std::vector& dims, + const std::vector* symbolic_dims) { + ThrowOnError(GetApi().CreateTensorTypeAndShapeInfo(&p_)); + ThrowOnError(GetApi().SetTensorElementType(p_, element_type)); + ThrowOnError(GetApi().SetDimensions(p_, dims.data(), dims.size())); + + if (symbolic_dims) { + std::vector symbolic_dims_cstr; + symbolic_dims_cstr.reserve(symbolic_dims->size()); + std::transform(symbolic_dims->begin(), symbolic_dims->end(), std::back_inserter(symbolic_dims_cstr), + [](const std::string& s) { return s.c_str(); }); + ThrowOnError(GetApi().SetSymbolicDimensions(p_, symbolic_dims_cstr.data(), symbolic_dims_cstr.size())); + } +} + +#if !defined(ORT_MINIMAL_BUILD) +// static +inline TypeInfo TypeInfo::CreateTensorInfo(ConstTensorTypeAndShapeInfo tensor_type_and_shape_info) { + OrtTypeInfo* output = nullptr; + ThrowOnError(GetModelEditorApi().CreateTensorTypeInfo(tensor_type_and_shape_info, &output)); + return TypeInfo{output}; +} + +// static +inline TypeInfo TypeInfo::CreateSparseTensorInfo(ConstTensorTypeAndShapeInfo sparse_tensor_type_and_shape_info) { + OrtTypeInfo* output = nullptr; + ThrowOnError(GetModelEditorApi().CreateSparseTensorTypeInfo(sparse_tensor_type_and_shape_info, &output)); + return TypeInfo{output}; +} + +// static +inline TypeInfo TypeInfo::CreateSequenceTypeInfo(ConstTypeInfo sequence_type) { + OrtTypeInfo* output; + ThrowOnError(GetModelEditorApi().CreateSequenceTypeInfo(sequence_type, &output)); + return TypeInfo{output}; +} + +// static +inline TypeInfo TypeInfo::CreateMapTypeInfo(ONNXTensorElementDataType key_type, ConstTypeInfo value_type) { + OrtTypeInfo* output; + ThrowOnError(GetModelEditorApi().CreateMapTypeInfo(key_type, value_type, &output)); + return TypeInfo{output}; +} + +// static +inline TypeInfo TypeInfo::CreateOptionalTypeInfo(ConstTypeInfo contained_type) { + OrtTypeInfo* output; + ThrowOnError(GetModelEditorApi().CreateOptionalTypeInfo(contained_type, &output)); + return TypeInfo{output}; +} +#endif // #if !defined(ORT_MINIMAL_BUILD) + namespace detail { template @@ -1244,9 +1432,16 @@ inline void TensorTypeAndShapeInfoImpl::GetSymbolicDimensions(const char** va ThrowOnError(GetApi().GetSymbolicDimensions(this->p_, values, values_count)); } +template +inline std::vector TensorTypeAndShapeInfoImpl::GetSymbolicDimensions() const { + std::vector out(GetDimensionsCount(), nullptr); + ThrowOnError(GetApi().GetSymbolicDimensions(this->p_, out.data(), out.size())); + return out; +} + template inline std::vector TensorTypeAndShapeInfoImpl::GetShape() const { - std::vector out(GetDimensionsCount(), 0); + std::vector out(GetDimensionsCount(), -1); ThrowOnError(GetApi().GetDimensions(this->p_, out.data(), out.size())); return out; } @@ -1560,23 +1755,35 @@ void ValueImpl::FillSparseTensorBlockSparse(const OrtMemoryInfo* data_mem_inf } // namespace detail template -inline Value Value::CreateTensor(const OrtMemoryInfo* info, T* p_data, size_t p_data_element_count, const int64_t* shape, size_t shape_len) { +inline Value Value::CreateTensor(const OrtMemoryInfo* info, T* p_data, size_t p_data_element_count, + const int64_t* shape, size_t shape_len) { return CreateTensor(info, p_data, p_data_element_count * sizeof(T), shape, shape_len, TypeToTensorType::type); } -inline Value Value::CreateTensor(const OrtMemoryInfo* info, void* p_data, size_t p_data_byte_count, const int64_t* shape, size_t shape_len, +inline Value Value::CreateTensor(const OrtMemoryInfo* info, void* p_data, size_t p_data_byte_count, + const int64_t* shape, size_t shape_len, ONNXTensorElementDataType type) { OrtValue* out; ThrowOnError(GetApi().CreateTensorWithDataAsOrtValue(info, p_data, p_data_byte_count, shape, shape_len, type, &out)); return Value{out}; } +inline Value Value::CreateTensor(OrtAllocator* deleter, void* p_data, size_t p_data_byte_count, + const int64_t* shape, size_t shape_len, + ONNXTensorElementDataType type) { + OrtValue* out; + ThrowOnError(GetApi().CreateTensorWithDataAndDeleterAsOrtValue(deleter, p_data, p_data_byte_count, + shape, shape_len, type, &out)); + return Value{out}; +} + template inline Value Value::CreateTensor(OrtAllocator* allocator, const int64_t* shape, size_t shape_len) { return CreateTensor(allocator, shape, shape_len, TypeToTensorType::type); } -inline Value Value::CreateTensor(OrtAllocator* allocator, const int64_t* shape, size_t shape_len, ONNXTensorElementDataType type) { +inline Value Value::CreateTensor(OrtAllocator* allocator, const int64_t* shape, size_t shape_len, + ONNXTensorElementDataType type) { OrtValue* out; ThrowOnError(GetApi().CreateTensorAsOrtValue(allocator, shape, shape_len, type, &out)); return Value{out}; @@ -1594,7 +1801,8 @@ inline Value Value::CreateSparseTensor(const OrtMemoryInfo* info, void* p_data, const Shape& values_shape, ONNXTensorElementDataType type) { OrtValue* out; ThrowOnError(GetApi().CreateSparseTensorWithValuesAsOrtValue(info, p_data, dense_shape.shape, dense_shape.shape_len, - values_shape.shape, values_shape.shape_len, type, &out)); + values_shape.shape, values_shape.shape_len, type, + &out)); return Value{out}; } @@ -2167,4 +2375,142 @@ inline const OrtOpAttr* ShapeInferContext::GetAttrHdl(const char* attr_name) con return attr_hdl; } +namespace detail { +inline std::vector StringsToCharPtrs(const std::vector& strings) { + std::vector ptrs; + ptrs.reserve(strings.size()); + std::transform(strings.begin(), strings.end(), std::back_inserter(ptrs), + [](const std::string& s) { return s.c_str(); }); + + return ptrs; +} +} // namespace detail + +#if !defined(ORT_MINIMAL_BUILD) +// static +inline void Node::Init(const std::string& operator_name, const std::string& operator_domain, + const std::string& node_name, + const std::vector& input_names, + const std::vector& output_names, + std::vector& attributes, + OrtNode*& node) { + auto inputs = detail::StringsToCharPtrs(input_names); + auto outputs = detail::StringsToCharPtrs(output_names); + + std::vector attributes_ptrs; + attributes_ptrs.reserve(attributes.size()); + std::transform(attributes.begin(), attributes.end(), std::back_inserter(attributes_ptrs), + [](OpAttr& attr) -> OrtOpAttr* { return attr; }); + + ThrowOnError(GetModelEditorApi().CreateNode(operator_name.c_str(), operator_domain.c_str(), node_name.c_str(), + inputs.data(), inputs.size(), + outputs.data(), outputs.size(), + attributes_ptrs.data(), attributes_ptrs.size(), + &node)); + + // Node now owns the attributes + std::for_each(attributes.begin(), attributes.end(), [](OpAttr& attr) { attr.release(); }); +} + +inline Node::Node(const std::string& operator_name, const std::string& operator_domain, + const std::string& node_name, + const std::vector& input_names, + const std::vector& output_names, + std::vector& attributes) { + Init(operator_name, operator_domain, node_name, input_names, output_names, attributes, p_); +} + +inline Node::Node(const std::string& operator_name, const std::string& operator_domain, + const std::string& node_name, + const std::vector& input_names, + const std::vector& output_names) { + std::vector empty_attributes; + Init(operator_name, operator_domain, node_name, input_names, output_names, empty_attributes, p_); +} + +inline Graph::Graph() { + ThrowOnError(GetModelEditorApi().CreateGraph(&p_)); +} + +inline Model::Model(const std::vector& opsets) { + std::vector domains; + std::vector versions; + domains.reserve(opsets.size()); + versions.reserve(opsets.size()); + + for (const auto& pair : opsets) { + domains.push_back(pair.first.c_str()); + versions.push_back(pair.second); + } + + ThrowOnError(GetModelEditorApi().CreateModel(domains.data(), versions.data(), opsets.size(), &p_)); +} + +inline ValueInfo::ValueInfo(const std::string& name, const ConstTypeInfo& type_info) { + ThrowOnError(GetModelEditorApi().CreateValueInfo(name.c_str(), type_info, &p_)); +} +#endif // !defined(ORT_MINIMAL_BUILD) + +namespace detail { +template <> +inline std::string ValueInfoImpl::Name() const { + const char* name = nullptr; + ThrowOnError(GetApi().GetValueInfoName(this->p_, &name)); + return name; +} + +template <> +inline ConstTypeInfo ValueInfoImpl::TypeInfo() const { + const OrtTypeInfo* type_info = nullptr; + ThrowOnError(GetApi().GetValueInfoTypeInfo(this->p_, &type_info)); + return ConstTypeInfo{type_info}; +} + +#if !defined(ORT_MINIMAL_BUILD) +template <> +inline void GraphImpl::SetInputs(std::vector& inputs) { + std::vector inputs_ptrs; + inputs_ptrs.reserve(inputs.size()); + std::transform(inputs.begin(), inputs.end(), std::back_inserter(inputs_ptrs), + [](ValueInfo& vi) -> OrtValueInfo* { return vi; }); + + ThrowOnError(GetModelEditorApi().SetGraphInputs(p_, inputs_ptrs.data(), inputs_ptrs.size())); + + // Graph now owns the inputs + std::for_each(inputs.begin(), inputs.end(), [](ValueInfo& vi) { vi.release(); }); +} + +template <> +inline void GraphImpl::SetOutputs(std::vector& outputs) { + std::vector outputs_ptrs; + outputs_ptrs.reserve(outputs.size()); + std::transform(outputs.begin(), outputs.end(), std::back_inserter(outputs_ptrs), + [](ValueInfo& vi) -> OrtValueInfo* { return vi; }); + + ThrowOnError(GetModelEditorApi().SetGraphOutputs(p_, outputs_ptrs.data(), outputs_ptrs.size())); + + // Graph now owns the outputs + std::for_each(outputs.begin(), outputs.end(), [](ValueInfo& vi) { vi.release(); }); +} + +template <> +inline void GraphImpl::AddInitializer(const std::string& name, Value& initializer, bool data_is_external) { + // Graph takes ownership of `initializer` + ThrowOnError(GetModelEditorApi().AddInitializerToGraph(p_, name.c_str(), initializer.release(), data_is_external)); +} + +template <> +inline void GraphImpl::AddNode(Node& node) { + // Graph takes ownership of `node` + ThrowOnError(GetModelEditorApi().AddNodeToGraph(p_, node.release())); +} + +template <> +inline void ModelImpl::AddGraph(Graph& graph) { + // Model takes ownership of `graph` + ThrowOnError(GetModelEditorApi().AddGraphToModel(p_, graph.release())); +} +#endif // !defined(ORT_MINIMAL_BUILD) + +} // namespace detail } // namespace Ort diff --git a/include/onnxruntime/core/session/onnxruntime_run_options_config_keys.h b/include/onnxruntime/core/session/onnxruntime_run_options_config_keys.h index c80b8c0c164b6..f40ea6591059e 100644 --- a/include/onnxruntime/core/session/onnxruntime_run_options_config_keys.h +++ b/include/onnxruntime/core/session/onnxruntime_run_options_config_keys.h @@ -43,6 +43,9 @@ static const char* const kOrtRunOptionsConfigQnnPerfModePostRun = "qnn.htp_perf_ // Set RPC control latency for QNN HTP backend static const char* const kOrtRunOptionsConfigQnnRpcControlLatency = "qnn.rpc_control_latency"; +// Set QNN Lora Config File for apply Lora in QNN context binary +static const char* const kOrtRunOptionsConfigQnnLoraConfig = "qnn.lora_config"; + // Set graph annotation id for CUDA EP. Use with enable_cuda_graph=true. // The value should be an integer. If the value is not set, the default value is 0 and // ORT session only captures one cuda graph before another capture is requested. diff --git a/include/onnxruntime/core/session/onnxruntime_session_options_config_keys.h b/include/onnxruntime/core/session/onnxruntime_session_options_config_keys.h index 117a2cdabca2f..af1f9c04b2831 100644 --- a/include/onnxruntime/core/session/onnxruntime_session_options_config_keys.h +++ b/include/onnxruntime/core/session/onnxruntime_session_options_config_keys.h @@ -315,9 +315,12 @@ static const char* const kOrtSessionOptionEpContextEmbedMode = "ep.context_embed // in case user need to merge/connect multiple EPContext nodes in one model static const char* const kOrtSessionOptionEpContextNodeNamePrefix = "ep.context_node_name_prefix"; -// Share EP related resources across EPs +// Share EP related resources across sessions static const char* const kOrtSessionOptionShareEpContexts = "ep.share_ep_contexts"; +// Stop to share EP related resources across sessions from then on +static const char* const kOrtSessionOptionStopShareEpContexts = "ep.stop_share_ep_contexts"; + // Use this config when dumping EP context model with an external initializers file // All initializers will be inside the external data file if specified, otherwise all in Onnx file static const char* const kOrtSessionOptionsEpContextModelExternalInitializersFileName = diff --git a/java/src/test/android/app/src/androidTest/java/ai/onnxruntime/example/javavalidator/SimpleTest.kt b/java/src/test/android/app/src/androidTest/java/ai/onnxruntime/example/javavalidator/SimpleTest.kt index 5e6bee6cac9f4..0af8b6f1a8ab1 100644 --- a/java/src/test/android/app/src/androidTest/java/ai/onnxruntime/example/javavalidator/SimpleTest.kt +++ b/java/src/test/android/app/src/androidTest/java/ai/onnxruntime/example/javavalidator/SimpleTest.kt @@ -82,9 +82,7 @@ class SimpleTest { OrtProvider.QNN -> { if (OrtEnvironment.getAvailableProviders().contains(OrtProvider.QNN)) { - // Since this is running in an Android environment, we use the .so library - val qnnLibrary = "libQnnHtp.so" - val providerOptions = Collections.singletonMap("backend_path", qnnLibrary) + val providerOptions = Collections.singletonMap("backend_type", "htp") opts.addQnn(providerOptions) } else { Log.println(Log.INFO, TAG, "NO QNN EP available, skip the test") diff --git a/java/src/test/java/ai/onnxruntime/InferenceTest.java b/java/src/test/java/ai/onnxruntime/InferenceTest.java index e11537492d3a7..83cdc32dbaeb5 100644 --- a/java/src/test/java/ai/onnxruntime/InferenceTest.java +++ b/java/src/test/java/ai/onnxruntime/InferenceTest.java @@ -2125,13 +2125,8 @@ private static SqueezeNetTuple openSessionSqueezeNet(EnumSet provid options.addXnnpack(Collections.emptyMap()); break; case QNN: - { - String backendPath = OS.WINDOWS.isCurrentOs() ? "/QnnCpu.dll" : "/libQnnCpu.so"; - options.addQnn( - Collections.singletonMap( - "backend_path", TestHelpers.getResourcePath(backendPath).toString())); - break; - } + options.addQnn(Collections.singletonMap("backend_type", "cpu")); + break; case VITIS_AI: case RK_NPU: case MI_GRAPH_X: diff --git a/js/.eslintrc.js b/js/.eslintrc.js index 462e417df1d66..f20adcb0eaa52 100644 --- a/js/.eslintrc.js +++ b/js/.eslintrc.js @@ -185,10 +185,9 @@ module.exports = { '_OrtCreateTensor', '_OrtEndProfiling', '_OrtFree', - '_OrtGetInputName', '_OrtGetInputOutputCount', + '_OrtGetInputOutputMetadata', '_OrtGetLastError', - '_OrtGetOutputName', '_OrtGetTensorData', '_OrtInit', '_OrtReleaseBinding', diff --git a/js/README.md b/js/README.md index 635f5faa54981..eb95c9224c081 100644 --- a/js/README.md +++ b/js/README.md @@ -361,7 +361,7 @@ From ORT v1.19 onwards, the ONNX Runtime Mobile packages are no longer published From `/js/react_native, ```sh - yarn bootstrap + npm run bootstrap ``` When testing with a custom built ONNX Runtime Android package, copy `/aar_out/MinSizeRel/com/microsoft/onnxruntime/onnxruntime-android//onnxruntime-android-.aar` into the `/js/react_native/e2e/android/app/libs` directory. @@ -377,7 +377,7 @@ From ORT v1.19 onwards, the ONNX Runtime Mobile packages are no longer published Install detox command line tools: ``` - yarn global add detox-cli + npm install -g detox-cli ``` Install applesimutils which is required by Detox to work with iOS simulators. (Requires a MacOS device) @@ -439,13 +439,13 @@ From ORT v1.19 onwards, the ONNX Runtime Mobile packages are no longer published To record logs for testing results, add `--record-logs`. Output logs and test results will be produced in the `e2e/artifacts/` folder. See: [Detox/logger#artifacts](https://wix.github.io/Detox/docs/api/logger#artifacts) - **_`yarn bootstrap` changes `packages.json` and `yarn.lock` files. Once testing is done, restore changes to avoid unwanted commit._** + **_`npm run bootstrap` changes `packages.json` and `package-lock.json` files. Once testing is done, restore changes to avoid unwanted commit._** 5. Run Android and iOS apps. ```sh - yarn e2e android - yarn e2e ios + npm run e2e:android + npm run e2e:ios ``` ### NPM Packaging @@ -460,4 +460,4 @@ From ORT v1.19 onwards, the ONNX Runtime Mobile packages are no longer published ### Distribution -It should be able to consumed by React Native projects that uses Yarn packages through `yarn add onnxruntime-react-native`. +It should be able to consumed by React Native projects that uses npm packages through `npm install onnxruntime-react-native`. diff --git a/js/build_webgpu.bat b/js/build_webgpu.bat new file mode 100644 index 0000000000000..95413509e701d --- /dev/null +++ b/js/build_webgpu.bat @@ -0,0 +1,79 @@ +@echo off + +rem build_webgpu.bat --- build onnxruntime-web with WebGPU EP +rem +rem Usage: +rem build_webgpu.bat config [clean] +rem +rem Options: +rem config Build configuration, "d" or "r" +rem clean Perform a clean build, "clean" or empty + +setlocal enabledelayedexpansion + +set ROOT=%~dp0..\ +set BUILD_DIR=%ROOT%build_webgpu + +:arg1 +if ["%~1"]==["d"] ( + set CONFIG=Debug + set CONFIG_EXTRA_FLAG= + @rem --enable_wasm_profiling --wasm_run_tests_in_browser + @rem --cmake_extra_defines onnxruntime_ENABLE_WEBASSEMBLY_OUTPUT_OPTIMIZED_MODEL=1 + @rem --enable_wasm_debug_info + goto :arg2 +) +if ["%~1"]==["r"] ( + set CONFIG=Release + set CONFIG_EXTRA_FLAG= + @rem --enable_wasm_api_exception_catching --disable_rtti + goto :arg2 +) +echo Invalid configuration "%~1", must be "d"(Debug) or "r"(Release) +exit /b 1 + +:arg2 +if ["%~2"]==["clean"] ( + goto :clean +) +if not exist "%ROOT%js\web\dist" ( + goto :npm_ci +) + +goto :build_wasm + +:clean +if exist "%BUILD_DIR%" ( + rd /s /q %BUILD_DIR% +) + +pushd %ROOT% +git submodule sync --recursive +git submodule update --init --recursive +popd + +:npm_ci +pushd %ROOT%js +call npm ci +popd +pushd %ROOT%js\common +call npm ci +popd +pushd %ROOT%js\web +call npm ci +call npm run pull:wasm +popd + +:build_wasm + +set PATH=C:\Program Files\Git\usr\bin;%PATH% + +call %ROOT%build.bat --config %CONFIG% %CONFIG_EXTRA_FLAG% --skip_submodule_sync --build_wasm --target onnxruntime_webassembly --skip_tests^ + --enable_wasm_simd --enable_wasm_threads --use_jsep --use_webnn --use_webgpu --build_dir %BUILD_DIR% + +IF NOT "%ERRORLEVEL%" == "0" ( + exit /b %ERRORLEVEL% +) + +copy /Y %BUILD_DIR%\%CONFIG%\ort-wasm-simd-threaded.jsep.wasm %ROOT%js\web\dist\ +copy /Y %BUILD_DIR%\%CONFIG%\ort-wasm-simd-threaded.jsep.mjs %ROOT%js\web\dist\ diff --git a/js/common/lib/backend.ts b/js/common/lib/backend.ts index e63f9c6c9147f..9b7c1db219188 100644 --- a/js/common/lib/backend.ts +++ b/js/common/lib/backend.ts @@ -23,6 +23,9 @@ interface SessionHandler { readonly inputNames: readonly string[]; readonly outputNames: readonly string[]; + + readonly inputMetadata: readonly InferenceSession.ValueMetadata[]; + readonly outputMetadata: readonly InferenceSession.ValueMetadata[]; } /** diff --git a/js/common/lib/env.ts b/js/common/lib/env.ts index d6d9f7fa48790..112c8a1f78851 100644 --- a/js/common/lib/env.ts +++ b/js/common/lib/env.ts @@ -41,16 +41,22 @@ export declare namespace Env { numThreads?: number; /** - * set or get a boolean value indicating whether to enable SIMD. If set to false, SIMD will be forcely disabled. + * set a value indicating whether to enable SIMD. + * + * ONNX Runtime will perform feature detection based on the value of this property. Specifically, when the value is + * set to: + * - `undefined`, `true` or `"fixed"`: will check availability of Fixed-width SIMD. + * - `"relaxed"`: will check availability of Relaxed SIMD. + * - `false`: will not perform SIMD feature checking. + * + * Setting this property does not make ONNX Runtime to switch to the corresponding runtime automatically. User need + * to set `wasmPaths` or `wasmBinary` property to load the corresponding runtime. * * This setting is available only when WebAssembly SIMD feature is available in current context. * * @defaultValue `true` - * - * @deprecated This property is deprecated. Since SIMD is supported by all major JavaScript engines, non-SIMD - * build is no longer provided. This property will be removed in future release. */ - simd?: boolean; + simd?: boolean | 'fixed' | 'relaxed'; /** * set or get a boolean value indicating whether to enable trace. diff --git a/js/common/lib/inference-session-impl.ts b/js/common/lib/inference-session-impl.ts index d47ed7a331045..797dba8b94089 100644 --- a/js/common/lib/inference-session-impl.ts +++ b/js/common/lib/inference-session-impl.ts @@ -225,5 +225,13 @@ export class InferenceSession implements InferenceSessionInterface { return this.handler.outputNames; } + get inputMetadata(): readonly InferenceSessionInterface.ValueMetadata[] { + return this.handler.inputMetadata; + } + + get outputMetadata(): readonly InferenceSessionInterface.ValueMetadata[] { + return this.handler.outputMetadata; + } + private handler: InferenceSessionHandler; } diff --git a/js/common/lib/inference-session.ts b/js/common/lib/inference-session.ts index 26784be41ca7c..4ef4891b5b46a 100644 --- a/js/common/lib/inference-session.ts +++ b/js/common/lib/inference-session.ts @@ -4,6 +4,7 @@ import { InferenceSession as InferenceSessionImpl } from './inference-session-impl.js'; import { OnnxModelOptions } from './onnx-model.js'; import { OnnxValue, OnnxValueDataLocation } from './onnx-value.js'; +import type { Tensor } from './tensor.js'; import { TryGetGlobalType } from './type-helper.js'; /* eslint-disable @typescript-eslint/no-redeclare */ @@ -309,9 +310,15 @@ export declare namespace InferenceSession { export interface QnnExecutionProviderOption extends ExecutionProviderOption { readonly name: 'qnn'; /** - * Specify a path to the QnnHtp.dll file. + * Specify the QNN backend type. E.g., 'cpu' or 'htp'. + * Mutually exclusive with `backendPath`. * - * @default 'QnnHtp.dll' + * @default 'htp' + */ + backendType?: string; + /** + * Specify a path to the QNN backend library. + * Mutually exclusive with `backendType`. */ backendPath?: string; /** @@ -430,11 +437,53 @@ export declare namespace InferenceSession { // #region value metadata - // eslint-disable-next-line @typescript-eslint/no-empty-interface - interface ValueMetadata { - // TBD + /** + * The common part of the value metadata type for both tensor and non-tensor values. + */ + export interface ValueMetadataBase { + /** + * The name of the specified input or output. + */ + readonly name: string; + } + + /** + * Represents the metadata of a non-tensor value. + */ + export interface NonTensorValueMetadata extends ValueMetadataBase { + /** + * Get a value indicating whether the value is a tensor. + */ + readonly isTensor: false; } + /** + * Represents the metadata of a tensor value. + */ + export interface TensorValueMetadata extends ValueMetadataBase { + /** + * Get a value indicating whether the value is a tensor. + */ + readonly isTensor: true; + /** + * Get the data type of the tensor. + */ + readonly type: Tensor.Type; + /** + * Get the shape of the tensor. + * + * If the shape is not defined, the value will an empty array. Otherwise, it will be an array representing the shape + * of the tensor. Each element in the array can be a number or a string. If the element is a number, it represents + * the corresponding dimension size. If the element is a string, it represents a symbolic dimension. + */ + readonly shape: ReadonlyArray; + } + + /** + * Represents the metadata of a value. + */ + export type ValueMetadata = NonTensorValueMetadata | TensorValueMetadata; + // #endregion } @@ -505,15 +554,15 @@ export interface InferenceSession { */ readonly outputNames: readonly string[]; - // /** - // * Get input metadata of the loaded model. - // */ - // readonly inputMetadata: ReadonlyArray>; + /** + * Get input metadata of the loaded model. + */ + readonly inputMetadata: readonly InferenceSession.ValueMetadata[]; - // /** - // * Get output metadata of the loaded model. - // */ - // readonly outputMetadata: ReadonlyArray>; + /** + * Get output metadata of the loaded model. + */ + readonly outputMetadata: readonly InferenceSession.ValueMetadata[]; // #endregion } diff --git a/js/common/lib/version.ts b/js/common/lib/version.ts index 475dfe0d4888b..8ec54c0bd22dc 100644 --- a/js/common/lib/version.ts +++ b/js/common/lib/version.ts @@ -4,4 +4,4 @@ // This file is generated by /js/scripts/update-version.ts // Do not modify file content manually. -export const version = '1.21.0'; +export const version = '1.22.0'; diff --git a/js/common/package-lock.json b/js/common/package-lock.json index 4d92e0f73aa69..b8a3351ae3867 100644 --- a/js/common/package-lock.json +++ b/js/common/package-lock.json @@ -1,12 +1,12 @@ { "name": "onnxruntime-common", - "version": "1.21.0", + "version": "1.22.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "onnxruntime-common", - "version": "1.21.0", + "version": "1.22.0", "license": "MIT", "devDependencies": { "typedoc": "^0.25.7" diff --git a/js/common/package.json b/js/common/package.json index e220e9c81d693..2d331bb42e4c7 100644 --- a/js/common/package.json +++ b/js/common/package.json @@ -2,7 +2,7 @@ "license": "MIT", "type": "module", "name": "onnxruntime-common", - "version": "1.21.0", + "version": "1.22.0", "repository": { "url": "https://github.com/Microsoft/onnxruntime.git", "type": "git" diff --git a/js/node/lib/backend.ts b/js/node/lib/backend.ts index 004a3c890a7e4..bea9debcfdd4d 100644 --- a/js/node/lib/backend.ts +++ b/js/node/lib/backend.ts @@ -5,6 +5,32 @@ import { Backend, InferenceSession, InferenceSessionHandler, SessionHandler } fr import { Binding, binding, initOrt } from './binding'; +const dataTypeStrings = [ + undefined, // 0 + 'float32', + 'uint8', + 'int8', + 'uint16', + 'int16', + 'int32', + 'int64', + 'string', + 'bool', + 'float16', + 'float64', + 'uint32', + 'uint64', + undefined, // 14 + undefined, // 15 + undefined, // 16 + undefined, // 17 + undefined, // 18 + undefined, // 19 + undefined, // 20 + 'uint4', + 'int4', +] as const; + class OnnxruntimeSessionHandler implements InferenceSessionHandler { #inferenceSession: Binding.InferenceSession; @@ -17,8 +43,56 @@ class OnnxruntimeSessionHandler implements InferenceSessionHandler { } else { this.#inferenceSession.loadModel(pathOrBuffer.buffer, pathOrBuffer.byteOffset, pathOrBuffer.byteLength, options); } - this.inputNames = this.#inferenceSession.inputNames; - this.outputNames = this.#inferenceSession.outputNames; + + // prepare input/output names and metadata + this.inputNames = []; + this.outputNames = []; + this.inputMetadata = []; + this.outputMetadata = []; + + // this function takes raw metadata from binding and returns a tuple of the following 2 items: + // - an array of string representing names + // - an array of converted InferenceSession.ValueMetadata + const fillNamesAndMetadata = ( + rawMetadata: readonly Binding.ValueMetadata[], + ): [names: string[], metadata: InferenceSession.ValueMetadata[]] => { + const names: string[] = []; + const metadata: InferenceSession.ValueMetadata[] = []; + + for (const m of rawMetadata) { + names.push(m.name); + if (!m.isTensor) { + metadata.push({ name: m.name, isTensor: false }); + } else { + const type = dataTypeStrings[m.type]; + if (type === undefined) { + throw new Error(`Unsupported data type: ${m.type}`); + } + const shape: Array = []; + for (let i = 0; i < m.shape.length; ++i) { + const dim = m.shape[i]; + if (dim === -1) { + shape.push(m.symbolicDimensions[i]); + } else if (dim >= 0) { + shape.push(dim); + } else { + throw new Error(`Invalid dimension: ${dim}`); + } + } + metadata.push({ + name: m.name, + isTensor: m.isTensor, + type, + shape, + }); + } + } + + return [names, metadata]; + }; + + [this.inputNames, this.inputMetadata] = fillNamesAndMetadata(this.#inferenceSession.inputMetadata); + [this.outputNames, this.outputMetadata] = fillNamesAndMetadata(this.#inferenceSession.outputMetadata); } async dispose(): Promise { @@ -28,6 +102,9 @@ class OnnxruntimeSessionHandler implements InferenceSessionHandler { readonly inputNames: string[]; readonly outputNames: string[]; + readonly inputMetadata: InferenceSession.ValueMetadata[]; + readonly outputMetadata: InferenceSession.ValueMetadata[]; + startProfiling(): void { // startProfiling is a no-op. // diff --git a/js/node/lib/binding.ts b/js/node/lib/binding.ts index 56203f5a5ca02..ed133734ce66a 100644 --- a/js/node/lib/binding.ts +++ b/js/node/lib/binding.ts @@ -19,12 +19,19 @@ type RunOptions = InferenceSession.RunOptions; * Binding exports a simple synchronized inference session object wrap. */ export declare namespace Binding { + export interface ValueMetadata { + name: string; + isTensor: boolean; + symbolicDimensions: string[]; + shape: number[]; + type: number; + } export interface InferenceSession { loadModel(modelPath: string, options: SessionOptions): void; loadModel(buffer: ArrayBuffer, byteOffset: number, byteLength: number, options: SessionOptions): void; - readonly inputNames: string[]; - readonly outputNames: string[]; + readonly inputMetadata: ValueMetadata[]; + readonly outputMetadata: ValueMetadata[]; run(feeds: FeedsType, fetches: FetchesType, options: RunOptions): ReturnType; diff --git a/js/node/lib/version.ts b/js/node/lib/version.ts index 475dfe0d4888b..8ec54c0bd22dc 100644 --- a/js/node/lib/version.ts +++ b/js/node/lib/version.ts @@ -4,4 +4,4 @@ // This file is generated by /js/scripts/update-version.ts // Do not modify file content manually. -export const version = '1.21.0'; +export const version = '1.22.0'; diff --git a/js/node/package-lock.json b/js/node/package-lock.json index a18b7bb14feb5..41ffb071b9ced 100644 --- a/js/node/package-lock.json +++ b/js/node/package-lock.json @@ -1,12 +1,12 @@ { "name": "onnxruntime-node", - "version": "1.21.0", + "version": "1.22.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "onnxruntime-node", - "version": "1.21.0", + "version": "1.22.0", "hasInstallScript": true, "license": "MIT", "os": [ @@ -30,7 +30,7 @@ }, "../common": { "name": "onnxruntime-common", - "version": "1.21.0", + "version": "1.22.0", "license": "MIT", "devDependencies": { "typedoc": "^0.25.7" @@ -277,10 +277,11 @@ "dev": true }, "node_modules/axios": { - "version": "1.7.9", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", - "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.2.tgz", + "integrity": "sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==", "dev": true, + "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -1782,9 +1783,9 @@ "dev": true }, "axios": { - "version": "1.7.9", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", - "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.2.tgz", + "integrity": "sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==", "dev": true, "requires": { "follow-redirects": "^1.15.6", diff --git a/js/node/package.json b/js/node/package.json index e5c5d8cbf6abc..195e252f1064b 100644 --- a/js/node/package.json +++ b/js/node/package.json @@ -13,7 +13,7 @@ 3 ] }, - "version": "1.21.0", + "version": "1.22.0", "dependencies": { "global-agent": "^3.0.0", "onnxruntime-common": "file:../common", diff --git a/js/node/script/install.js b/js/node/script/install.js index 7fdaeb9586278..d406da3591eec 100644 --- a/js/node/script/install.js +++ b/js/node/script/install.js @@ -9,7 +9,6 @@ // The purpose of this script is to download the required binaries for the platform and architecture. // Currently, most of the binaries are already bundled in the package, except for the following: -// - Linux/x64/CUDA 11 // - Linux/x64/CUDA 12 // // The CUDA binaries are not bundled because they are too large to be allowed in the npm registry. Instead, they are diff --git a/js/node/src/inference_session_wrap.cc b/js/node/src/inference_session_wrap.cc index 04ab71dc48ec2..5512b418b5cfb 100644 --- a/js/node/src/inference_session_wrap.cc +++ b/js/node/src/inference_session_wrap.cc @@ -34,8 +34,8 @@ Napi::Object InferenceSessionWrap::Init(Napi::Env env, Napi::Object exports) { InstanceMethod("run", &InferenceSessionWrap::Run), InstanceMethod("dispose", &InferenceSessionWrap::Dispose), InstanceMethod("endProfiling", &InferenceSessionWrap::EndProfiling), - InstanceAccessor("inputNames", &InferenceSessionWrap::GetInputNames, nullptr, napi_default, nullptr), - InstanceAccessor("outputNames", &InferenceSessionWrap::GetOutputNames, nullptr, napi_default, nullptr)}); + InstanceAccessor("inputMetadata", &InferenceSessionWrap::GetMetadata, nullptr, napi_default, reinterpret_cast(true)), + InstanceAccessor("outputMetadata", &InferenceSessionWrap::GetMetadata, nullptr, napi_default, reinterpret_cast(false))}); wrappedSessionConstructor = Napi::Persistent(func); wrappedSessionConstructor.SuppressDestruct(); @@ -120,27 +120,17 @@ Napi::Value InferenceSessionWrap::LoadModel(const Napi::CallbackInfo& info) { size_t count = session_->GetInputCount(); inputNames_.reserve(count); for (size_t i = 0; i < count; i++) { - auto inp_name = session_->GetInputNameAllocated(i, allocator); - inputNames_.emplace_back(inp_name.get()); - auto typeInfo = session_->GetInputTypeInfo(i); - auto onnxType = typeInfo.GetONNXType(); - inputTypes_.emplace_back(onnxType); - inputTensorElementDataTypes_.emplace_back(onnxType == ONNX_TYPE_TENSOR - ? typeInfo.GetTensorTypeAndShapeInfo().GetElementType() - : ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED); + auto input_name = session_->GetInputNameAllocated(i, allocator); + inputNames_.emplace_back(input_name.get()); + inputTypes_.push_back(session_->GetInputTypeInfo(i)); } count = session_->GetOutputCount(); outputNames_.reserve(count); for (size_t i = 0; i < count; i++) { - auto out_name = session_->GetOutputNameAllocated(i, allocator); - outputNames_.emplace_back(out_name.get()); - auto typeInfo = session_->GetOutputTypeInfo(i); - auto onnxType = typeInfo.GetONNXType(); - outputTypes_.emplace_back(onnxType); - outputTensorElementDataTypes_.emplace_back(onnxType == ONNX_TYPE_TENSOR - ? typeInfo.GetTensorTypeAndShapeInfo().GetElementType() - : ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED); + auto output_name = session_->GetOutputNameAllocated(i, allocator); + outputNames_.emplace_back(output_name.get()); + outputTypes_.push_back(session_->GetOutputTypeInfo(i)); } // cache preferred output locations @@ -157,22 +147,32 @@ Napi::Value InferenceSessionWrap::LoadModel(const Napi::CallbackInfo& info) { return env.Undefined(); } -Napi::Value InferenceSessionWrap::GetInputNames(const Napi::CallbackInfo& info) { +Napi::Value InferenceSessionWrap::GetMetadata(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); ORT_NAPI_THROW_ERROR_IF(!this->initialized_, env, "Session is not initialized."); ORT_NAPI_THROW_ERROR_IF(this->disposed_, env, "Session already disposed."); Napi::EscapableHandleScope scope(env); - return scope.Escape(CreateNapiArrayFrom(env, inputNames_)); -} - -Napi::Value InferenceSessionWrap::GetOutputNames(const Napi::CallbackInfo& info) { - Napi::Env env = info.Env(); - ORT_NAPI_THROW_ERROR_IF(!this->initialized_, env, "Session is not initialized."); - ORT_NAPI_THROW_ERROR_IF(this->disposed_, env, "Session already disposed."); - - Napi::EscapableHandleScope scope(env); - return scope.Escape(CreateNapiArrayFrom(env, outputNames_)); + auto& names = info.Data() != nullptr ? inputNames_ : outputNames_; + auto& types = info.Data() != nullptr ? inputTypes_ : outputTypes_; + auto array = Napi::Array::New(env, types.size()); + for (uint32_t i = 0; i < types.size(); i++) { + Napi::Object obj = Napi::Object::New(env); + obj.Set("name", names[i]); + auto& typeInfo = types[i]; + if (typeInfo.GetONNXType() == ONNX_TYPE_TENSOR) { + obj.Set("isTensor", true); + + auto tensorInfo = typeInfo.GetTensorTypeAndShapeInfo(); + obj.Set("type", static_cast>(tensorInfo.GetElementType())); + obj.Set("symbolicDimensions", CreateNapiArrayFrom(env, tensorInfo.GetSymbolicDimensions())); + obj.Set("shape", CreateNapiArrayFrom(env, tensorInfo.GetShape())); + } else { + obj.Set("isTensor", false); + } + array.Set(i, Napi::Value::From(env, obj)); + } + return scope.Escape(array); } Napi::Value InferenceSessionWrap::Run(const Napi::CallbackInfo& info) { diff --git a/js/node/src/inference_session_wrap.h b/js/node/src/inference_session_wrap.h index 0b3dd1178c807..776cdc0d3b51e 100644 --- a/js/node/src/inference_session_wrap.h +++ b/js/node/src/inference_session_wrap.h @@ -45,19 +45,12 @@ class InferenceSessionWrap : public Napi::ObjectWrap { // following functions have to be called after model is loaded. /** - * [sync] get input names. + * [sync] get metadata of the model's inputs or outputs. * @param nothing - * @returns a string array. + * @returns an array of objects with keys: name, isTensor, type, symbolicDimensions, shape * @throw nothing */ - Napi::Value GetInputNames(const Napi::CallbackInfo& info); - /** - * [sync] get output names. - * @param nothing - * @returns a string array. - * @throw nothing - */ - Napi::Value GetOutputNames(const Napi::CallbackInfo& info); + Napi::Value GetMetadata(const Napi::CallbackInfo& info); /** * [sync] run the model. @@ -98,11 +91,9 @@ class InferenceSessionWrap : public Napi::ObjectWrap { // input/output metadata std::vector inputNames_; - std::vector inputTypes_; - std::vector inputTensorElementDataTypes_; + std::vector inputTypes_; std::vector outputNames_; - std::vector outputTypes_; - std::vector outputTensorElementDataTypes_; + std::vector outputTypes_; // preferred output locations std::vector preferredOutputLocations_; diff --git a/js/node/src/session_options_helper.cc b/js/node/src/session_options_helper.cc index 1ac61ba4e2e81..3c607d88e5402 100644 --- a/js/node/src/session_options_helper.cc +++ b/js/node/src/session_options_helper.cc @@ -83,6 +83,14 @@ void ParseExecutionProviders(const Napi::Array epList, Ort::SessionOptions& sess #endif #ifdef USE_QNN if (name == "qnn") { + Napi::Value backend_type = obj.Get("backendType"); + if (!backend_type.IsUndefined()) { + if (backend_type.IsString()) { + qnn_options["backend_type"] = backend_type.As().Utf8Value(); + } else { + ORT_NAPI_THROW_TYPEERROR(epList.Env(), "Invalid argument: backendType must be a string."); + } + } Napi::Value backend_path = obj.Get("backendPath"); if (!backend_path.IsUndefined()) { if (backend_path.IsString()) { @@ -136,11 +144,6 @@ void ParseExecutionProviders(const Napi::Array epList, Ort::SessionOptions& sess #endif #ifdef USE_QNN } else if (name == "qnn") { - // Ensure that the backend_path option are set to default values if not provided. - if (qnn_options.find("backend_path") == qnn_options.end()) { - qnn_options["backend_path"] = "QnnHtp.dll"; - } - sessionOptions.AppendExecutionProvider("QNN", qnn_options); #endif } else { diff --git a/js/node/test/test-main.ts b/js/node/test/test-main.ts index fc792179d3373..6e7905a24711a 100644 --- a/js/node/test/test-main.ts +++ b/js/node/test/test-main.ts @@ -15,6 +15,7 @@ warmup(); // unittests require('./unittests/lib/index'); require('./unittests/lib/inference-session'); +require('./unittests/lib/model-metadata'); require('./unittests/lib/tensor'); // E2E tests diff --git a/js/node/test/unittests/lib/model-metadata.ts b/js/node/test/unittests/lib/model-metadata.ts new file mode 100644 index 0000000000000..e58c86d39a742 --- /dev/null +++ b/js/node/test/unittests/lib/model-metadata.ts @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import * as assert from 'assert'; +import { InferenceSession } from 'onnxruntime-common'; + +const ONNX_MODEL_TEST_ABS_NO_SHAPE = Uint8Array.from([ + 8, 9, 58, 73, 10, 31, 10, 7, 105, 110, 112, 117, 116, 95, 48, 18, 8, 111, 117, 116, 112, 117, 116, 95, 48, 26, 3, 65, + 98, 115, 34, 3, 65, 98, 115, 58, 0, 18, 3, 97, 98, 115, 90, 15, 10, 7, 105, 110, 112, 117, 116, 95, 48, 18, 4, 10, 2, + 8, 1, 98, 16, 10, 8, 111, 117, 116, 112, 117, 116, 95, 48, 18, 4, 10, 2, 8, 1, 66, 4, 10, 0, 16, 21, +]); + +const ONNX_MODEL_TEST_ABS_SYMBOL = Uint8Array.from([ + 8, 9, 58, 105, 10, 31, 10, 7, 105, 110, 112, 117, 116, 95, 48, 18, 8, 111, 117, 116, 112, 117, 116, 95, 48, 26, 3, 65, + 98, 115, 34, 3, 65, 98, 115, 58, 0, 18, 3, 97, 98, 115, 90, 47, 10, 7, 105, 110, 112, 117, 116, 95, 48, 18, 36, 10, + 34, 8, 1, 18, 30, 10, 13, 18, 11, 95, 105, 110, 112, 117, 116, 95, 48, 95, 100, 48, 10, 13, 18, 11, 95, 105, 110, 112, + 117, 116, 95, 48, 95, 100, 49, 98, 16, 10, 8, 111, 117, 116, 112, 117, 116, 95, 48, 18, 4, 10, 2, 8, 1, 66, 4, 10, 0, + 16, 21, +]); + +const ONNX_MODEL_TEST_ABS_STATIC = Uint8Array.from([ + 8, 9, 58, 83, 10, 31, 10, 7, 105, 110, 112, 117, 116, 95, 48, 18, 8, 111, 117, 116, 112, 117, 116, 95, 48, 26, 3, 65, + 98, 115, 34, 3, 65, 98, 115, 58, 0, 18, 3, 97, 98, 115, 90, 25, 10, 7, 105, 110, 112, 117, 116, 95, 48, 18, 14, 10, + 12, 8, 1, 18, 8, 10, 2, 8, 2, 10, 2, 8, 4, 98, 16, 10, 8, 111, 117, 116, 112, 117, 116, 95, 48, 18, 4, 10, 2, 8, 1, + 66, 4, 10, 0, 16, 21, +]); + +const testModelMetadata = async ( + model: Uint8Array, + expectedInputNames: string[], + expectedOutputNames: string[], + expectedInputMetadata: InferenceSession.ValueMetadata[], + expectedOutputMetadata: InferenceSession.ValueMetadata[], +) => { + const session = await InferenceSession.create(model); + assert.deepStrictEqual(session.inputNames, expectedInputNames); + assert.deepStrictEqual(session.outputNames, expectedOutputNames); + assert.deepStrictEqual(session.inputMetadata, expectedInputMetadata); + assert.deepStrictEqual(session.outputMetadata, expectedOutputMetadata); +}; + +describe('#UnitTest# - test model input/output metadata', () => { + it('model input/output with no shape', async () => { + await testModelMetadata( + ONNX_MODEL_TEST_ABS_NO_SHAPE, + ['input_0'], + ['output_0'], + [{ name: 'input_0', isTensor: true, type: 'float32', shape: [] }], + [{ name: 'output_0', isTensor: true, type: 'float32', shape: [] }], + ); + }); + + it('model input/output with symbol shape', async () => { + await testModelMetadata( + ONNX_MODEL_TEST_ABS_SYMBOL, + ['input_0'], + ['output_0'], + [ + { + name: 'input_0', + isTensor: true, + type: 'float32', + shape: ['_input_0_d0', '_input_0_d1'], + }, + ], + [ + { + name: 'output_0', + isTensor: true, + type: 'float32', + shape: ['_input_0_d0', '_input_0_d1'], + }, + ], + ); + }); + + it('model input/output with static shape', async () => { + await testModelMetadata( + ONNX_MODEL_TEST_ABS_STATIC, + ['input_0'], + ['output_0'], + [{ name: 'input_0', isTensor: true, type: 'float32', shape: [2, 4] }], + [{ name: 'output_0', isTensor: true, type: 'float32', shape: [2, 4] }], + ); + }); +}); diff --git a/js/package-lock.json b/js/package-lock.json index 1fa9032ff6d3c..dbbf42d9c8f35 100644 --- a/js/package-lock.json +++ b/js/package-lock.json @@ -4,6 +4,7 @@ "requires": true, "packages": { "": { + "name": "js", "license": "MIT", "devDependencies": { "@types/fs-extra": "^11.0.4", diff --git a/js/react_native/README.md b/js/react_native/README.md index b45182d16a3fc..f7b118e81573d 100644 --- a/js/react_native/README.md +++ b/js/react_native/README.md @@ -13,7 +13,7 @@ With ONNX Runtime React Native, React Native developers can score pre-trained ON ### Installation ```sh -yarn add onnxruntime-react-native +npm install onnxruntime-react-native ``` ### Usage diff --git a/js/react_native/android/gradle.properties b/js/react_native/android/gradle.properties index 3461ce4919d38..6f0e50c7151a8 100644 --- a/js/react_native/android/gradle.properties +++ b/js/react_native/android/gradle.properties @@ -4,7 +4,7 @@ # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. # Default value: -Xmx1024m -XX:MaxPermSize=256m -org.gradle.jvmargs=-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -Djavax.xml.accessExternalSchema=all -Djavax.xml.accessExternalDTD=all +org.gradle.jvmargs=-Xmx8192m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -Djavax.xml.accessExternalSchema=all -Djavax.xml.accessExternalDTD=all # # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit @@ -13,7 +13,7 @@ org.gradle.jvmargs=-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF #Tue Jan 26 17:36:02 PST 2021 android.enableJetifier=true android.useAndroidX=true -OnnxruntimeModule_buildToolsVersion=33.0.0 +OnnxruntimeModule_buildToolsVersion=34.0.0 OnnxruntimeModule_compileSdkVersion=34 OnnxruntimeModule_minSdkVersion=24 OnnxruntimeModule_targetSdkVersion=34 diff --git a/js/react_native/android/src/main/AndroidManifest.xml b/js/react_native/android/src/main/AndroidManifest.xml index c6e3cb45e16e5..8713bb2c6b8cd 100644 --- a/js/react_native/android/src/main/AndroidManifest.xml +++ b/js/react_native/android/src/main/AndroidManifest.xml @@ -1,3 +1,3 @@ + package="ai.onnxruntime.reactnative"> diff --git a/js/react_native/babel.config.js b/js/react_native/babel.config.js deleted file mode 100644 index e2240f1f51f8b..0000000000000 --- a/js/react_native/babel.config.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -module.exports = { - presets: ['module:metro-react-native-babel-preset'], -}; diff --git a/js/react_native/e2e/.detoxrc.js b/js/react_native/e2e/.detoxrc.js index e886a363d378b..1d49f06213e51 100644 --- a/js/react_native/e2e/.detoxrc.js +++ b/js/react_native/e2e/.detoxrc.js @@ -38,8 +38,8 @@ module.exports = { simulator: { type: 'ios.simulator', device: { - type: 'iPhone 14', - os: 'iOS 16.4', + type: 'iPhone 15', + os: 'iOS 17.4', }, }, attached: { diff --git a/js/react_native/e2e/android/app/build.gradle b/js/react_native/e2e/android/app/build.gradle index 68eaacc1908c3..fa94c00a32bd0 100644 --- a/js/react_native/e2e/android/app/build.gradle +++ b/js/react_native/e2e/android/app/build.gradle @@ -1,8 +1,7 @@ apply plugin: "com.android.application" +apply plugin: "org.jetbrains.kotlin.android" apply plugin: "com.facebook.react" -import com.android.build.OutputFile - /** * This is the configuration block to customize your React Native Android app. * By default you don't need to apply any configuration, just uncomment the lines you need. @@ -13,8 +12,8 @@ react { // root = file("../") // The folder where the react-native NPM package is. Default is ../node_modules/react-native // reactNativeDir = file("../node_modules/react-native") - // The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen - // codegenDir = file("../node_modules/react-native-codegen") + // The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen + // codegenDir = file("../node_modules/@react-native/codegen") // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js // cliFile = file("../node_modules/react-native/cli.js") @@ -52,14 +51,6 @@ react { // hermesFlags = ["-O", "-output-source-map"] } -/** - * Set this to true to create four separate APKs instead of one, - * one for each native architecture. This is useful if you don't - * use App Bundles (https://developer.android.com/guide/app-bundle/) - * and want to have separate APKs to upload to the Play Store. - */ -def enableSeparateBuildPerCPUArchitecture = false - /** * Set this to true to Run Proguard on Release builds to minify the Java bytecode. */ @@ -78,20 +69,12 @@ def enableProguardInReleaseBuilds = false */ def jscFlavor = 'org.webkit:android-jsc:+' -/** - * Private function to get the list of Native Architectures you want to build. - * This reads the value from reactNativeArchitectures in your gradle.properties - * file and works together with the --active-arch-only flag of react-native run-android. - */ -def reactNativeArchitectures() { - def value = project.getProperties().get("reactNativeArchitectures") - return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] -} android { + buildToolsVersion rootProject.ext.buildToolsVersion compileSdkVersion rootProject.ext.compileSdkVersion - namespace "com.example.reactnativeonnxruntimemodule" + namespace "com.reactnativeonnxruntimemodule" compileOptions { sourceCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_17 @@ -99,9 +82,13 @@ android { packagingOptions { pickFirst '**/libc++_shared.so' pickFirst '**/libfbjni.so' + excludes = [ + "META-INF", + "META-INF/**", + ] } defaultConfig { - applicationId "com.example.reactnativeonnxruntimemodule" + applicationId "com.reactnativeonnxruntimemodule" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 @@ -109,14 +96,6 @@ android { testBuildType System.getProperty('testBuildType', 'debug') testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } - splits { - abi { - reset() - enable enableSeparateBuildPerCPUArchitecture - universalApk false // If true, also generate a universal APK - include "armeabi-v7a", "x86", "arm64-v8a", "x86_64" - } - } signingConfigs { debug { storeFile rootProject.file('debug.keystore') @@ -135,20 +114,6 @@ android { proguardFile "${rootProject.projectDir}/../node_modules/detox/android/detox/proguard-rules-app.pro" } } - // applicationVariants are e.g. debug, release - applicationVariants.all { variant -> - variant.outputs.each { output -> - // For each separate APK per architecture, set a unique version code as described here: - // https://developer.android.com/studio/build/configure-apk-splits.html - def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] - def abi = output.getFilter(OutputFile.ABI) - if (abi != null) { // null for the universal-debug, universal-release variants - output.versionCodeOverride = - versionCodes.get(abi) * 1048576 + defaultConfig.versionCode - } - - } - } } repositories { @@ -164,19 +129,8 @@ dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) // The version of react-native is set by the React Native Gradle Plugin implementation("com.facebook.react:react-android") - - implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" + implementation("com.facebook.react:flipper-integration") implementation 'androidx.test.ext:junit:1.1.5' - debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") { - exclude group:'com.facebook.fbjni' - } - debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { - exclude group:'com.facebook.flipper' - exclude group:'com.squareup.okhttp3', module:'okhttp' - } - debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") { - exclude group:'com.facebook.flipper' - } if (hermesEnabled.toBoolean()) { implementation("com.facebook.react:hermes-android") @@ -188,7 +142,7 @@ dependencies { androidTestImplementation "androidx.test:runner:1.5.2" androidTestImplementation "androidx.test:rules:1.5.0" - implementation project(':onnxruntime-react-native') + implementation (project(':onnxruntime-react-native')) // specify ORT dependency here so it can be found in libs flatDir repository implementation "com.microsoft.onnxruntime:onnxruntime-android:latest.integration@aar" } diff --git a/js/react_native/e2e/android/app/src/androidTest/java/com/example/reactnativeonnxruntimemodule/DetoxTest.java b/js/react_native/e2e/android/app/src/androidTest/java/com/reactnativeonnxruntimemodule/DetoxTest.java similarity index 96% rename from js/react_native/e2e/android/app/src/androidTest/java/com/example/reactnativeonnxruntimemodule/DetoxTest.java rename to js/react_native/e2e/android/app/src/androidTest/java/com/reactnativeonnxruntimemodule/DetoxTest.java index 9425e1365fedf..4a5142a60ebc6 100644 --- a/js/react_native/e2e/android/app/src/androidTest/java/com/example/reactnativeonnxruntimemodule/DetoxTest.java +++ b/js/react_native/e2e/android/app/src/androidTest/java/com/reactnativeonnxruntimemodule/DetoxTest.java @@ -2,7 +2,7 @@ // Detox requires the project to have a single dummy native Android Test with some special content, // which will be picked up by the testRunner. -package com.example.reactnativeonnxruntimemodule; +package com.reactnativeonnxruntimemodule; import android.content.Intent; diff --git a/js/react_native/e2e/android/app/src/debug/AndroidManifest.xml b/js/react_native/e2e/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index fa26aa56e1c14..0000000000000 --- a/js/react_native/e2e/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - diff --git a/js/react_native/e2e/android/app/src/debug/java/com/example/reactnativeonnxruntimemodule/ReactNativeFlipper.java b/js/react_native/e2e/android/app/src/debug/java/com/example/reactnativeonnxruntimemodule/ReactNativeFlipper.java deleted file mode 100644 index 3f0a2311b6b6f..0000000000000 --- a/js/react_native/e2e/android/app/src/debug/java/com/example/reactnativeonnxruntimemodule/ReactNativeFlipper.java +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - *

This source code is licensed under the MIT license found in the LICENSE file in the root - * directory of this source tree. - */ -package com.example.reactnativeonnxruntimemodule; - -import android.content.Context; -import com.facebook.flipper.android.AndroidFlipperClient; -import com.facebook.flipper.android.utils.FlipperUtils; -import com.facebook.flipper.core.FlipperClient; -import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin; -import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin; -import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin; -import com.facebook.flipper.plugins.inspector.DescriptorMapping; -import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin; -import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor; -import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; -import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; -import com.facebook.react.ReactInstanceEventListener; -import com.facebook.react.ReactInstanceManager; -import com.facebook.react.bridge.ReactContext; -import com.facebook.react.modules.network.NetworkingModule; -import okhttp3.OkHttpClient; - -/** - * Class responsible of loading Flipper inside your React Native application. This is the debug - * flavor of it. Here you can add your own plugins and customize the Flipper setup. - */ -public class ReactNativeFlipper { - public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { - if (FlipperUtils.shouldEnableFlipper(context)) { - final FlipperClient client = AndroidFlipperClient.getInstance(context); - - client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults())); - client.addPlugin(new DatabasesFlipperPlugin(context)); - client.addPlugin(new SharedPreferencesFlipperPlugin(context)); - client.addPlugin(CrashReporterPlugin.getInstance()); - - NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin(); - NetworkingModule.setCustomClientBuilder( - new NetworkingModule.CustomClientBuilder() { - @Override - public void apply(OkHttpClient.Builder builder) { - builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin)); - } - }); - client.addPlugin(networkFlipperPlugin); - client.start(); - - // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized - // Hence we run if after all native modules have been initialized - ReactContext reactContext = reactInstanceManager.getCurrentReactContext(); - if (reactContext == null) { - reactInstanceManager.addReactInstanceEventListener( - new ReactInstanceEventListener() { - @Override - public void onReactContextInitialized(ReactContext reactContext) { - reactInstanceManager.removeReactInstanceEventListener(this); - reactContext.runOnNativeModulesQueueThread( - new Runnable() { - @Override - public void run() { - client.addPlugin(new FrescoFlipperPlugin()); - } - }); - } - }); - } else { - client.addPlugin(new FrescoFlipperPlugin()); - } - } - } -} \ No newline at end of file diff --git a/js/react_native/e2e/android/app/src/main/AndroidManifest.xml b/js/react_native/e2e/android/app/src/main/AndroidManifest.xml index d219c7c18f3c2..a44d8099522a9 100644 --- a/js/react_native/e2e/android/app/src/main/AndroidManifest.xml +++ b/js/react_native/e2e/android/app/src/main/AndroidManifest.xml @@ -24,7 +24,6 @@ - diff --git a/js/react_native/e2e/android/app/src/main/java/com/example/reactnativeonnxruntimemodule/MainActivity.java b/js/react_native/e2e/android/app/src/main/java/com/example/reactnativeonnxruntimemodule/MainActivity.java deleted file mode 100644 index e2e48633ddb6e..0000000000000 --- a/js/react_native/e2e/android/app/src/main/java/com/example/reactnativeonnxruntimemodule/MainActivity.java +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.example.reactnativeonnxruntimemodule; - -import com.facebook.react.ReactActivity; - -public class MainActivity extends ReactActivity { - /** - * Returns the name of the main component registered from JavaScript. This is used to schedule - * rendering of the component. - */ - @Override - protected String getMainComponentName() { - return "OnnxruntimeModuleExample"; - } -} diff --git a/js/react_native/e2e/android/app/src/main/java/com/example/reactnativeonnxruntimemodule/MainApplication.java b/js/react_native/e2e/android/app/src/main/java/com/example/reactnativeonnxruntimemodule/MainApplication.java deleted file mode 100644 index 2c59e5dd3d3b1..0000000000000 --- a/js/react_native/e2e/android/app/src/main/java/com/example/reactnativeonnxruntimemodule/MainApplication.java +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.example.reactnativeonnxruntimemodule; - -import ai.onnxruntime.reactnative.OnnxruntimePackage; -import android.app.Application; -import android.content.Context; -import com.facebook.react.PackageList; -import com.facebook.react.ReactApplication; -import com.facebook.react.ReactInstanceManager; -import com.facebook.react.ReactNativeHost; -import com.facebook.react.ReactPackage; -import com.facebook.soloader.SoLoader; -import java.lang.reflect.InvocationTargetException; -import java.util.List; - -public class MainApplication extends Application implements ReactApplication { - private static Context appContext; - - private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { - @Override - public boolean getUseDeveloperSupport() { - return BuildConfig.DEBUG; - } - - @Override - protected List getPackages() { - @SuppressWarnings("UnnecessaryLocalVariable") List packages = new PackageList(this).getPackages(); - packages.add(new DataHandlerPackage()); - - return packages; - } - - @Override - protected String getJSMainModuleName() { - return "index"; - } - }; - - @Override - public ReactNativeHost getReactNativeHost() { - return mReactNativeHost; - } - - @Override - public void onCreate() { - super.onCreate(); - appContext = getApplicationContext(); - SoLoader.init(this, /* native exopackage */ false); - initializeFlipper( - this, getReactNativeHost().getReactInstanceManager()); // Remove this line if you don't want Flipper enabled - } - - public static Context getAppContext() { return appContext; } - - /** - * Loads Flipper in React Native templates. - * - * @param context - */ - private static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { - if (BuildConfig.DEBUG) { - try { - /* - We use reflection here to pick up the class that initializes Flipper, - since Flipper library is not available in release mode - */ - Class aClass = Class.forName("com.onnxruntimereactnativeExample.ReactNativeFlipper"); - aClass.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class) - .invoke(null, context, reactInstanceManager); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - } - } -} diff --git a/js/react_native/e2e/android/app/src/main/java/com/example/reactnativeonnxruntimemodule/DataHandlerPackage.java b/js/react_native/e2e/android/app/src/main/java/com/reactnativeonnxruntimemodule/DataHandlerPackage.java similarity index 94% rename from js/react_native/e2e/android/app/src/main/java/com/example/reactnativeonnxruntimemodule/DataHandlerPackage.java rename to js/react_native/e2e/android/app/src/main/java/com/reactnativeonnxruntimemodule/DataHandlerPackage.java index fa321e15c615b..adfd4e0bb755a 100644 --- a/js/react_native/e2e/android/app/src/main/java/com/example/reactnativeonnxruntimemodule/DataHandlerPackage.java +++ b/js/react_native/e2e/android/app/src/main/java/com/reactnativeonnxruntimemodule/DataHandlerPackage.java @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.example.reactnativeonnxruntimemodule; +package com.reactnativeonnxruntimemodule; import com.facebook.react.ReactPackage; import com.facebook.react.bridge.NativeModule; diff --git a/js/react_native/e2e/android/app/src/main/java/com/example/reactnativeonnxruntimemodule/MNISTDataHandler.java b/js/react_native/e2e/android/app/src/main/java/com/reactnativeonnxruntimemodule/MNISTDataHandler.java similarity index 97% rename from js/react_native/e2e/android/app/src/main/java/com/example/reactnativeonnxruntimemodule/MNISTDataHandler.java rename to js/react_native/e2e/android/app/src/main/java/com/reactnativeonnxruntimemodule/MNISTDataHandler.java index a458901b5314c..b5f58f39ea8ca 100644 --- a/js/react_native/e2e/android/app/src/main/java/com/example/reactnativeonnxruntimemodule/MNISTDataHandler.java +++ b/js/react_native/e2e/android/app/src/main/java/com/reactnativeonnxruntimemodule/MNISTDataHandler.java @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.example.reactnativeonnxruntimemodule; +package com.reactnativeonnxruntimemodule; import static java.util.stream.Collectors.joining; @@ -114,7 +114,7 @@ private WritableMap preprocess(String uri) throws Exception { final int imageHeight = 28; final int imageWidth = 28; - InputStream is = MainApplication.getAppContext().getContentResolver().openInputStream(Uri.parse(uri)); + InputStream is = reactContext.getContentResolver().openInputStream(Uri.parse(uri)); BufferedInputStream bis = new BufferedInputStream(is); byte[] imageArray = new byte[bis.available()]; bis.read(imageArray); diff --git a/js/react_native/e2e/android/app/src/main/java/com/reactnativeonnxruntimemodule/MNISTPackage.java b/js/react_native/e2e/android/app/src/main/java/com/reactnativeonnxruntimemodule/MNISTPackage.java new file mode 100644 index 0000000000000..5b09a4b8aeea1 --- /dev/null +++ b/js/react_native/e2e/android/app/src/main/java/com/reactnativeonnxruntimemodule/MNISTPackage.java @@ -0,0 +1,28 @@ +package com.reactnativeonnxruntimemodule; + +import com.facebook.react.ReactPackage; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.uimanager.ViewManager; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class MNISTPackage implements ReactPackage { + @Override + public List createNativeModules(ReactApplicationContext reactContext) { + List modules = new ArrayList<>(); + try { + modules.add(new MNISTDataHandler(reactContext)); + } catch (Exception e) { + throw new RuntimeException("Failed to initialize MNISTDataHandler", e); + } + return modules; + } + + @Override + public List createViewManagers(ReactApplicationContext reactContext) { + return Collections.emptyList(); + } +} \ No newline at end of file diff --git a/js/react_native/e2e/android/app/src/main/java/com/reactnativeonnxruntimemodule/MainActivity.kt b/js/react_native/e2e/android/app/src/main/java/com/reactnativeonnxruntimemodule/MainActivity.kt new file mode 100644 index 0000000000000..e572f50dfdab1 --- /dev/null +++ b/js/react_native/e2e/android/app/src/main/java/com/reactnativeonnxruntimemodule/MainActivity.kt @@ -0,0 +1,22 @@ +package com.reactnativeonnxruntimemodule + +import com.facebook.react.ReactActivity +import com.facebook.react.ReactActivityDelegate +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled +import com.facebook.react.defaults.DefaultReactActivityDelegate + +class MainActivity : ReactActivity() { + + /** + * Returns the name of the main component registered from JavaScript. This is used to schedule + * rendering of the component. + */ + override fun getMainComponentName(): String = "OnnxruntimeModuleExample" + + /** + * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] + * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] + */ + override fun createReactActivityDelegate(): ReactActivityDelegate = + DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) +} \ No newline at end of file diff --git a/js/react_native/e2e/android/app/src/main/java/com/reactnativeonnxruntimemodule/MainApplication.kt b/js/react_native/e2e/android/app/src/main/java/com/reactnativeonnxruntimemodule/MainApplication.kt new file mode 100644 index 0000000000000..f28660d9915e5 --- /dev/null +++ b/js/react_native/e2e/android/app/src/main/java/com/reactnativeonnxruntimemodule/MainApplication.kt @@ -0,0 +1,53 @@ +package com.reactnativeonnxruntimemodule + +import android.app.Application +import android.content.Context +import com.facebook.react.PackageList +import com.facebook.react.ReactApplication +import com.facebook.react.ReactHost +import com.facebook.react.ReactNativeHost +import com.facebook.react.ReactPackage +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load +import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost +import com.facebook.react.defaults.DefaultReactNativeHost +import com.facebook.react.flipper.ReactNativeFlipper +import com.facebook.soloader.SoLoader + +class MainApplication : Application(), ReactApplication { + companion object { + private lateinit var appContext: Context + + fun getAppContext(): Context { + return appContext + } + } + override val reactNativeHost: ReactNativeHost = + object : DefaultReactNativeHost(this) { + override fun getPackages(): List = + PackageList(this).packages.apply { + // Packages that cannot be autolinked yet can be added manually here, for example: + // add(MyReactNativePackage()) + add(MNISTPackage()) + } + + override fun getJSMainModuleName(): String = "index" + + override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG + + override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED + override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED + } + + override val reactHost: ReactHost + get() = getDefaultReactHost(this.applicationContext, reactNativeHost) + override fun onCreate() { + super.onCreate() + appContext = applicationContext + SoLoader.init(this, false) + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + // If you opted-in for the New Architecture, we load the native entry point for this app. + load() + } + ReactNativeFlipper.initializeFlipper(this, reactNativeHost.reactInstanceManager) + } +} \ No newline at end of file diff --git a/js/react_native/e2e/android/build.gradle b/js/react_native/e2e/android/build.gradle index abe57d3d4521d..9ad8256fc52dc 100644 --- a/js/react_native/e2e/android/build.gradle +++ b/js/react_native/e2e/android/build.gradle @@ -2,11 +2,11 @@ buildscript { ext { - buildToolsVersion = "33.0.0" + buildToolsVersion = "34.0.0" minSdkVersion = 24 compileSdkVersion = 34 targetSdkVersion = 34 - kotlinVersion = "1.5.30" + kotlinVersion = "1.8.0" } repositories { google() @@ -14,9 +14,11 @@ buildscript { } dependencies { classpath('com.android.tools.build:gradle:7.4.2') - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") classpath("com.facebook.react:react-native-gradle-plugin") + + // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } @@ -43,3 +45,5 @@ allprojects { maven { url 'https://www.jitpack.io' } } } + +apply plugin: "com.facebook.react.rootproject" \ No newline at end of file diff --git a/js/react_native/e2e/android/gradle.properties b/js/react_native/e2e/android/gradle.properties index 92d178de62ce2..ede6147623f19 100644 --- a/js/react_native/e2e/android/gradle.properties +++ b/js/react_native/e2e/android/gradle.properties @@ -19,9 +19,7 @@ android.useAndroidX=true android.enableJetifier=true -FLIPPER_VERSION=0.182.0 -org.gradle.jvmargs=-Xmx4096M - +org.gradle.jvmargs=-Xmx8192m -XX:MaxMetaspaceSize=2048m -Dkotlin.daemon.jvm.options=-Xmx8192m # Use this property to enable or disable the Hermes JS engine. # If set to false, you will be using JSC instead. hermesEnabled=false diff --git a/js/react_native/e2e/android/gradle/wrapper/gradle-wrapper.properties b/js/react_native/e2e/android/gradle/wrapper/gradle-wrapper.properties index 36268b17b88ae..d11cdd907dd9d 100644 --- a/js/react_native/e2e/android/gradle/wrapper/gradle-wrapper.properties +++ b/js/react_native/e2e/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/js/react_native/e2e/babel.config.js b/js/react_native/e2e/babel.config.js deleted file mode 100644 index 96ef381f7825d..0000000000000 --- a/js/react_native/e2e/babel.config.js +++ /dev/null @@ -1,18 +0,0 @@ -'use strict'; - -const path = require('path'); -const pak = require('../package.json'); - -module.exports = { - presets: ['module:metro-react-native-babel-preset'], - plugins: [ - [ - 'module-resolver', - { - alias: { - [pak.name]: path.join(__dirname, '..', pak.source), - }, - }, - ], - ], -}; diff --git a/js/react_native/e2e/ios/OnnxruntimeModuleExample.xcodeproj/project.pbxproj b/js/react_native/e2e/ios/OnnxruntimeModuleExample.xcodeproj/project.pbxproj index 07604cd4beec9..e3a5a1447a68e 100644 --- a/js/react_native/e2e/ios/OnnxruntimeModuleExample.xcodeproj/project.pbxproj +++ b/js/react_native/e2e/ios/OnnxruntimeModuleExample.xcodeproj/project.pbxproj @@ -291,10 +291,15 @@ "${BUILT_PRODUCTS_DIR}/React-Codegen/React_Codegen.framework", "${BUILT_PRODUCTS_DIR}/React-Core/React.framework", "${BUILT_PRODUCTS_DIR}/React-CoreModules/CoreModules.framework", + "${BUILT_PRODUCTS_DIR}/React-Fabric/React_Fabric.framework", + "${BUILT_PRODUCTS_DIR}/React-FabricImage/React_FabricImage.framework", + "${BUILT_PRODUCTS_DIR}/React-ImageManager/React_ImageManager.framework", + "${BUILT_PRODUCTS_DIR}/React-Mapbuffer/React_Mapbuffer.framework", "${BUILT_PRODUCTS_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework", "${BUILT_PRODUCTS_DIR}/React-RCTAnimation/RCTAnimation.framework", "${BUILT_PRODUCTS_DIR}/React-RCTAppDelegate/React_RCTAppDelegate.framework", "${BUILT_PRODUCTS_DIR}/React-RCTBlob/RCTBlob.framework", + "${BUILT_PRODUCTS_DIR}/React-RCTFabric/RCTFabric.framework", "${BUILT_PRODUCTS_DIR}/React-RCTImage/RCTImage.framework", "${BUILT_PRODUCTS_DIR}/React-RCTLinking/RCTLinking.framework", "${BUILT_PRODUCTS_DIR}/React-RCTNetwork/RCTNetwork.framework", @@ -303,12 +308,16 @@ "${BUILT_PRODUCTS_DIR}/React-RCTVibration/RCTVibration.framework", "${BUILT_PRODUCTS_DIR}/React-cxxreact/cxxreact.framework", "${BUILT_PRODUCTS_DIR}/React-debug/React_debug.framework", - "${BUILT_PRODUCTS_DIR}/React-jsc/React_jsc.framework", + "${BUILT_PRODUCTS_DIR}/React-graphics/React_graphics.framework", + "${BUILT_PRODUCTS_DIR}/React-hermes/reacthermes.framework", + "${BUILT_PRODUCTS_DIR}/React-jserrorhandler/React_jserrorhandler.framework", "${BUILT_PRODUCTS_DIR}/React-jsi/jsi.framework", "${BUILT_PRODUCTS_DIR}/React-jsiexecutor/jsireact.framework", "${BUILT_PRODUCTS_DIR}/React-jsinspector/jsinspector.framework", "${BUILT_PRODUCTS_DIR}/React-logger/logger.framework", + "${BUILT_PRODUCTS_DIR}/React-nativeconfig/React_nativeconfig.framework", "${BUILT_PRODUCTS_DIR}/React-perflogger/reactperflogger.framework", + "${BUILT_PRODUCTS_DIR}/React-rendererdebug/React_rendererdebug.framework", "${BUILT_PRODUCTS_DIR}/React-runtimescheduler/React_runtimescheduler.framework", "${BUILT_PRODUCTS_DIR}/React-utils/React_utils.framework", "${BUILT_PRODUCTS_DIR}/ReactCommon/ReactCommon.framework", @@ -316,6 +325,8 @@ "${BUILT_PRODUCTS_DIR}/Yoga/yoga.framework", "${BUILT_PRODUCTS_DIR}/fmt/fmt.framework", "${BUILT_PRODUCTS_DIR}/glog/glog.framework", + "${BUILT_PRODUCTS_DIR}/libevent/libevent.framework", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( @@ -326,10 +337,15 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_Codegen.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CoreModules.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_Fabric.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_FabricImage.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_ImageManager.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_Mapbuffer.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_NativeModulesApple.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTAnimation.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_RCTAppDelegate.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTBlob.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTFabric.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTImage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTLinking.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTNetwork.framework", @@ -338,12 +354,16 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTVibration.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/cxxreact.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_debug.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_jsc.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_graphics.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/reacthermes.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_jserrorhandler.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/jsi.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/jsireact.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/jsinspector.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/logger.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_nativeconfig.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/reactperflogger.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_rendererdebug.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_runtimescheduler.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_utils.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReactCommon.framework", @@ -351,6 +371,8 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/yoga.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/fmt.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/glog.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libevent.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -447,7 +469,7 @@ "-ObjC", "-lc++", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.reactnativeonnxruntimemodule; + PRODUCT_BUNDLE_IDENTIFIER = com.reactnativeonnxruntimemodule; PRODUCT_NAME = OnnxruntimeModuleExample; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -471,7 +493,7 @@ "-ObjC", "-lc++", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.reactnativeonnxruntimemodule; + PRODUCT_BUNDLE_IDENTIFIER = com.reactnativeonnxruntimemodule; PRODUCT_NAME = OnnxruntimeModuleExample; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -484,7 +506,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(ARCHS_STANDARD)"; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -511,7 +533,7 @@ COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; - "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -535,6 +557,9 @@ "${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers/platform/ios", "${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers", "${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios", + " ${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers", + " ${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx", + " ${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers", ); "HEADER_SEARCH_PATHS[arch=*]" = ""; IPHONEOS_DEPLOYMENT_TARGET = 15.1; @@ -551,6 +576,7 @@ OTHER_LDFLAGS = "$(inherited)"; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; + USE_HERMES = true; }; name = Debug; }; @@ -560,7 +586,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(ARCHS_STANDARD)"; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -587,7 +613,7 @@ COPY_PHASE_STRIP = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -607,6 +633,9 @@ "${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers/platform/ios", "${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers", "${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios", + " ${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers", + " ${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx", + " ${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers", ); IPHONEOS_DEPLOYMENT_TARGET = 15.1; LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)"; @@ -621,6 +650,7 @@ OTHER_LDFLAGS = "$(inherited)"; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; + USE_HERMES = true; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/js/react_native/e2e/ios/OnnxruntimeModuleExample/Info.plist b/js/react_native/e2e/ios/OnnxruntimeModuleExample/Info.plist index d73af62336182..b8b2ff3059eb7 100644 --- a/js/react_native/e2e/ios/OnnxruntimeModuleExample/Info.plist +++ b/js/react_native/e2e/ios/OnnxruntimeModuleExample/Info.plist @@ -28,15 +28,12 @@ NSAllowsArbitraryLoads - NSExceptionDomains - - localhost - - NSExceptionAllowsInsecureHTTPLoads + + NSAllowsArbitraryLoads + + NSAllowsLocalNetworking - - NSLocationWhenInUseUsageDescription UILaunchStoryboardName diff --git a/js/react_native/e2e/ios/Podfile b/js/react_native/e2e/ios/Podfile index ba2226c144826..95c915cb41dca 100644 --- a/js/react_native/e2e/ios/Podfile +++ b/js/react_native/e2e/ios/Podfile @@ -19,11 +19,6 @@ target 'OnnxruntimeModuleExample' do use_react_native!( :path => config[:reactNativePath], - # Hermes is now enabled by default. Disable by setting this flag to false. - # Upcoming versions of React Native may rely on get_default_flags(), but - # we make it explicit here to aid in the React Native upgrade process. - - :hermes_enabled => false, # :flipper_configuration => FlipperConfiguration.enabled, :app_path => "#{Pod::Config.instance.installation_root}/.." ) @@ -43,6 +38,5 @@ target 'OnnxruntimeModuleExample' do config[:reactNativePath], :mac_catalyst_enabled => false, ) - __apply_Xcode_12_5_M1_post_install_workaround(installer) end end diff --git a/js/react_native/e2e/package-lock.json b/js/react_native/e2e/package-lock.json new file mode 100644 index 0000000000000..fff331486dfc1 --- /dev/null +++ b/js/react_native/e2e/package-lock.json @@ -0,0 +1,12747 @@ +{ + "name": "onnxruntime-reactnative-example", + "version": "0.5.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "onnxruntime-reactnative-example", + "version": "0.5.0", + "dependencies": { + "react": "^18.2.0", + "react-native": "^0.73.11", + "react-native-fs": "^2.20.0" + }, + "devDependencies": { + "@babel/core": "^7.20.0", + "@babel/preset-env": "^7.20.0", + "@babel/runtime": "^7.20.0", + "@react-native/babel-preset": "0.73.21", + "@react-native/eslint-config": "^0.73.2", + "@react-native/metro-config": "^0.73.5", + "@react-native/typescript-config": "0.73.1", + "@types/react": "^18.2.6", + "@types/react-test-renderer": "^18.0.0", + "babel-jest": "^29.6.3", + "detox": "20.10.0", + "eslint": "^8.19.0", + "jest": "^29.6.3", + "prettier": "^2.8.8", + "react-test-renderer": "18.2.0", + "typescript": "5.0.4" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@ampproject/remapping/node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", + "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/debug": { + "version": "4.3.4", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/core/node_modules/ms": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/@babel/eslint-parser": { + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.26.8.tgz", + "integrity": "sha512-3tBctaHRW6xSub26z7n8uyOTwwUsCdvIug/oxBH9n6yCO5hMj2vwDJAo7RbBMKrM7P+W2j61zLKviJQFGOYKMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0", + "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.9.tgz", + "integrity": "sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.26.9", + "@babel/types": "^7.26.9", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", + "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.25.2", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.26.9.tgz", + "integrity": "sha512-ubbUqCofvxPRurw5L8WTsCLSkQiVpov4Qx0WMA+jUN+nXBK8ADPlJO1grkFw5CWKC5+sZSOfuGMdX1aI1iT9Sg==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/helper-replace-supers": "^7.26.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/traverse": "^7.26.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz", + "integrity": "sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.3.1", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.13.0", + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/traverse": "^7.13.0", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0-0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/debug": { + "version": "4.3.4", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/ms": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", + "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz", + "integrity": "sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-wrap-function": "^7.25.0", + "@babel/traverse": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz", + "integrity": "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==", + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/traverse": "^7.26.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz", + "integrity": "sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz", + "integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.9.tgz", + "integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.9" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz", + "integrity": "sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz", + "integrity": "sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz", + "integrity": "sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", + "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.0.tgz", + "integrity": "sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", + "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead.", + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-export-default-from": { + "version": "7.17.12", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-export-default-from": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead.", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", + "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.16.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", + "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-default-from": { + "version": "7.16.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.26.0.tgz", + "integrity": "sha512-B+O2DnPc0iG+YXFqOxv2WNuNU97ToWjOomUQ78DouOENWUaM5sVrmet9mcomUGQFwpJd//gvUagXBSdzO1fRKg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.6.tgz", + "integrity": "sha512-aABl0jHw9bZ2karQ/uUD6XP4u0SG22SJrOHFoL6XB1R7dTovOP4TzTlsxOYC5yQ1pdscVK2JTUnF6QL3ARoAiQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.6.tgz", + "integrity": "sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", + "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", + "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.4.tgz", + "integrity": "sha512-jz8cV2XDDTqjKPwVPJBIjORVEmSGYhdRa8e5k5+vN+uwcjSrSxUaebBRa4ko1jqNF2uxyg8G6XYk30Jv285xzg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-remap-async-to-generator": "^7.25.0", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/traverse": "^7.25.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", + "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", + "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz", + "integrity": "sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.4.tgz", + "integrity": "sha512-nZeZHyCWPfjkdU5pA/uHiTaDAFUEqkpzf1YoQT2NeSynCGYq9rxfyI3XpQbfx/a0hSnFH6TGlEXvae5Vi7GD8g==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", + "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.4.tgz", + "integrity": "sha512-oexUfaQle2pF/b6E0dwsxQtAol9TLSO88kQvym6HHBWFliV2lGdrPieX+WgMRLSJDVzdYywk7jXbLPuO2KLTLg==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/traverse": "^7.25.4", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", + "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/template": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", + "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", + "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", + "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz", + "integrity": "sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", + "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", + "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", + "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.26.5.tgz", + "integrity": "sha512-eGK26RsbIkYUns3Y8qKl362juDDYK+wEdPGHGrhzUl6CewZFo55VZ7hg+CyMFU4dd5QQakBN86nBMpRsFpRvbQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/plugin-syntax-flow": "^7.26.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", + "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.25.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.1.tgz", + "integrity": "sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", + "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.2.tgz", + "integrity": "sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", + "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", + "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", + "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", + "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz", + "integrity": "sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", + "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", + "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", + "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", + "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", + "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", + "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", + "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", + "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", + "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", + "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.4.tgz", + "integrity": "sha512-ao8BG7E2b/URaUQGqN3Tlsg+M3KlHY6rJ1O1gXAEUnZoyNQnvKyH87Kfg+FoxSeyWUB8ISZZsC91C44ZuBFytw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", + "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", + "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.16.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.17.12", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-jsx": "^7.17.12", + "@babel/types": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.17.12", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.16.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", + "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", + "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.18.5", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", + "babel-plugin-polyfill-corejs2": "^0.3.0", + "babel-plugin-polyfill-corejs3": "^0.5.0", + "babel-plugin-polyfill-regenerator": "^0.3.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", + "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", + "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", + "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", + "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", + "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.8.tgz", + "integrity": "sha512-bME5J9AC8ChwA7aEPJ6zym3w7aObZULHhbNLU0bKUhKsAkylkzUdq+0kdymh9rzi8nlNFl2bmldFBCKNJBUpuw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-syntax-typescript": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", + "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", + "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", + "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.4.tgz", + "integrity": "sha512-qesBxiWkgN1Q+31xUE9RcMk79eOXXDCv6tfyGMRSs4RGlioSg2WVyQAm07k726cSE56pa+Kb0y9epX2qaXzTvA==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.4.tgz", + "integrity": "sha512-W9Gyo+KmcxjGahtt3t9fb14vFRWvPpu5pT6GBlovAK6BTBcxgjfVMSQCfJl4oi35ODrxP6xx2Wr8LNST57Mraw==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.25.4", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.3", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.0", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.0", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.0", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.24.7", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.4", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoped-functions": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", + "@babel/plugin-transform-class-properties": "^7.25.4", + "@babel/plugin-transform-class-static-block": "^7.24.7", + "@babel/plugin-transform-classes": "^7.25.4", + "@babel/plugin-transform-computed-properties": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-dotall-regex": "^7.24.7", + "@babel/plugin-transform-duplicate-keys": "^7.24.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.0", + "@babel/plugin-transform-dynamic-import": "^7.24.7", + "@babel/plugin-transform-exponentiation-operator": "^7.24.7", + "@babel/plugin-transform-export-namespace-from": "^7.24.7", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.25.1", + "@babel/plugin-transform-json-strings": "^7.24.7", + "@babel/plugin-transform-literals": "^7.25.2", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-member-expression-literals": "^7.24.7", + "@babel/plugin-transform-modules-amd": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-modules-systemjs": "^7.25.0", + "@babel/plugin-transform-modules-umd": "^7.24.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-new-target": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-numeric-separator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-object-super": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.25.4", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-property-literals": "^7.24.7", + "@babel/plugin-transform-regenerator": "^7.24.7", + "@babel/plugin-transform-reserved-words": "^7.24.7", + "@babel/plugin-transform-shorthand-properties": "^7.24.7", + "@babel/plugin-transform-spread": "^7.24.7", + "@babel/plugin-transform-sticky-regex": "^7.24.7", + "@babel/plugin-transform-template-literals": "^7.24.7", + "@babel/plugin-transform-typeof-symbol": "^7.24.8", + "@babel/plugin-transform-unicode-escapes": "^7.24.7", + "@babel/plugin-transform-unicode-property-regex": "^7.24.7", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.4", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.37.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", + "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", + "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.2", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", + "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-env/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/preset-env/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/@babel/preset-flow": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.25.9.tgz", + "integrity": "sha512-EASHsAhE+SSlEzJ4bzfusnXSHiU+JfAYzj+jbw2vgQKgq5HrUr8qs+vgtiEL5dOH6sEweI+PNt2D7AqrDSHyqQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-transform-flow-strip-types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.26.0.tgz", + "integrity": "sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-typescript": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/register": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.25.9.tgz", + "integrity": "sha512-8D43jXtGsYmEeDvm4MWHYUpWf8iiXgWYx3fW7E7Wb7Oe6FWqJPl5K6TuFW0dOwNZzEE5rjlaSJYH9JjrUKJszA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "find-cache-dir": "^2.0.0", + "make-dir": "^2.1.0", + "pirates": "^4.0.6", + "source-map-support": "^0.5.16" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/register/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "license": "MIT", + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@babel/register/node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "license": "MIT" + }, + "node_modules/@babel/runtime": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz", + "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime/node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" + }, + "node_modules/@babel/template": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz", + "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/parser": "^7.26.9", + "@babel/types": "^7.26.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.9.tgz", + "integrity": "sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.9", + "@babel/parser": "^7.26.9", + "@babel/template": "^7.26.9", + "@babel/types": "^7.26.9", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.3.4", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/traverse/node_modules/ms": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/@babel/types": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.9.tgz", + "integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@isaacs/ttlcache": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz", + "integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/create-cache-key-function": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz", + "integrity": "sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@jest/reporters/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.13", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "license": "MIT" + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-scope": "5.1.1" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@react-native-community/cli": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-12.3.7.tgz", + "integrity": "sha512-7+mOhk+3+X3BjSJZZvYrDJynA00gPYTlvT28ZjiLlbuVGfqfNiBKaxuF7rty+gjjpch4iKGvLhIhSN5cuOsdHQ==", + "license": "MIT", + "dependencies": { + "@react-native-community/cli-clean": "12.3.7", + "@react-native-community/cli-config": "12.3.7", + "@react-native-community/cli-debugger-ui": "12.3.7", + "@react-native-community/cli-doctor": "12.3.7", + "@react-native-community/cli-hermes": "12.3.7", + "@react-native-community/cli-plugin-metro": "12.3.7", + "@react-native-community/cli-server-api": "12.3.7", + "@react-native-community/cli-tools": "12.3.7", + "@react-native-community/cli-types": "12.3.7", + "chalk": "^4.1.2", + "commander": "^9.4.1", + "deepmerge": "^4.3.0", + "execa": "^5.0.0", + "find-up": "^4.1.0", + "fs-extra": "^8.1.0", + "graceful-fs": "^4.1.3", + "prompts": "^2.4.2", + "semver": "^7.5.2" + }, + "bin": { + "react-native": "build/bin.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native-community/cli-clean": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-12.3.7.tgz", + "integrity": "sha512-BCYW77QqyxfhiMEBOoHyciJRNV6Rhz1RvclReIKnCA9wAwmoJBeu4Mu+AwiECA2bUITX16fvPt3NwDsSd1jwfQ==", + "license": "MIT", + "dependencies": { + "@react-native-community/cli-tools": "12.3.7", + "chalk": "^4.1.2", + "execa": "^5.0.0" + } + }, + "node_modules/@react-native-community/cli-config": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-12.3.7.tgz", + "integrity": "sha512-IU2UhO9yj1rEBNhHWGzIXpPDzha4hizLP/PUOrhR4BUf6RVPUWEp+e1PXNGR0qjIf6esu7OC7t6mLOhH0NUJEw==", + "license": "MIT", + "dependencies": { + "@react-native-community/cli-tools": "12.3.7", + "chalk": "^4.1.2", + "cosmiconfig": "^5.1.0", + "deepmerge": "^4.3.0", + "glob": "^7.1.3", + "joi": "^17.2.1" + } + }, + "node_modules/@react-native-community/cli-debugger-ui": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-12.3.7.tgz", + "integrity": "sha512-UHUFrRdcjWSCdWG9KIp2QjuRIahBQnb9epnQI7JCq6NFbFHYfEI4rI7msjMn+gG8/tSwKTV2PTPuPmZ5wWlE7Q==", + "license": "MIT", + "dependencies": { + "serve-static": "^1.13.1" + } + }, + "node_modules/@react-native-community/cli-doctor": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-12.3.7.tgz", + "integrity": "sha512-gCamZztRoAyhciuQPqdz4Xe4t3gOdNsaADNd+rva+Rx8W2PoPeNv60i7/et06wlsn6B6Sh0/hMiAftJbiHDFkg==", + "license": "MIT", + "dependencies": { + "@react-native-community/cli-config": "12.3.7", + "@react-native-community/cli-platform-android": "12.3.7", + "@react-native-community/cli-platform-ios": "12.3.7", + "@react-native-community/cli-tools": "12.3.7", + "chalk": "^4.1.2", + "command-exists": "^1.2.8", + "deepmerge": "^4.3.0", + "envinfo": "^7.10.0", + "execa": "^5.0.0", + "hermes-profile-transformer": "^0.0.6", + "node-stream-zip": "^1.9.1", + "ora": "^5.4.1", + "semver": "^7.5.2", + "strip-ansi": "^5.2.0", + "wcwidth": "^1.0.1", + "yaml": "^2.2.1" + } + }, + "node_modules/@react-native-community/cli-doctor/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@react-native-community/cli-doctor/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@react-native-community/cli-doctor/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@react-native-community/cli-hermes": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-12.3.7.tgz", + "integrity": "sha512-ezzeiSKjRXK2+i1AAe7NhhN9CEHrgtRmTn2MAdBpE++N8fH5EQZgxFcGgGdwGvns2fm9ivyyeVnI5eAYwvM+jg==", + "license": "MIT", + "dependencies": { + "@react-native-community/cli-platform-android": "12.3.7", + "@react-native-community/cli-tools": "12.3.7", + "chalk": "^4.1.2", + "hermes-profile-transformer": "^0.0.6" + } + }, + "node_modules/@react-native-community/cli-platform-android": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-12.3.7.tgz", + "integrity": "sha512-mOltF3cpjNdJb3WSFwEHc1GH4ibCcnOvQ34OdWyblKy9ijuvG5SjNTlYR/UW/CURaDi3OUKAhxQMTY5d27bzGQ==", + "license": "MIT", + "dependencies": { + "@react-native-community/cli-tools": "12.3.7", + "chalk": "^4.1.2", + "execa": "^5.0.0", + "fast-xml-parser": "^4.2.4", + "glob": "^7.1.3", + "logkitty": "^0.7.1" + } + }, + "node_modules/@react-native-community/cli-platform-ios": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-12.3.7.tgz", + "integrity": "sha512-2WnVsMH4ORZIhBm/5nCms1NeeKG4KarNC7PMLmrXWXB/bibDcaNsjrJiqnmCUcpTEvTQTokRfoO7Aj6NM0Cqow==", + "license": "MIT", + "dependencies": { + "@react-native-community/cli-tools": "12.3.7", + "chalk": "^4.1.2", + "execa": "^5.0.0", + "fast-xml-parser": "^4.0.12", + "glob": "^7.1.3", + "ora": "^5.4.1" + } + }, + "node_modules/@react-native-community/cli-plugin-metro": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-12.3.7.tgz", + "integrity": "sha512-ahEw0Vfnv2Nv/jdZ2QDuGjQ9l2SczO4lXjb3ubu5vEYNLyTw3jYsLMK6iES7YQ/ApQmKdG476HU1O9uZdpaYPg==", + "license": "MIT" + }, + "node_modules/@react-native-community/cli-server-api": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-12.3.7.tgz", + "integrity": "sha512-LYETs3CCjrLn1ZU0kYv44TywiIl5IPFHZGeXhAh2TtgOk4mo3kvXxECDil9CdO3bmDra6qyiG61KHvzr8IrHdg==", + "license": "MIT", + "dependencies": { + "@react-native-community/cli-debugger-ui": "12.3.7", + "@react-native-community/cli-tools": "12.3.7", + "compression": "^1.7.1", + "connect": "^3.6.5", + "errorhandler": "^1.5.1", + "nocache": "^3.0.1", + "pretty-format": "^26.6.2", + "serve-static": "^1.13.1", + "ws": "^7.5.1" + } + }, + "node_modules/@react-native-community/cli-server-api/node_modules/@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@react-native-community/cli-server-api/node_modules/@types/yargs": { + "version": "15.0.19", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.19.tgz", + "integrity": "sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@react-native-community/cli-server-api/node_modules/pretty-format": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "license": "MIT", + "dependencies": { + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@react-native-community/cli-server-api/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "license": "MIT" + }, + "node_modules/@react-native-community/cli-tools": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-12.3.7.tgz", + "integrity": "sha512-7NL/1/i+wzd4fBr/FSr3ypR05tiU/Kv9l/M1sL1c6jfcDtWXAL90R161gQkQFK7shIQ8Idp0dQX1rq49tSyfQw==", + "license": "MIT", + "dependencies": { + "appdirsjs": "^1.2.4", + "chalk": "^4.1.2", + "find-up": "^5.0.0", + "mime": "^2.4.1", + "node-fetch": "^2.6.0", + "open": "^6.2.0", + "ora": "^5.4.1", + "semver": "^7.5.2", + "shell-quote": "^1.7.3", + "sudo-prompt": "^9.0.0" + } + }, + "node_modules/@react-native-community/cli-tools/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@react-native-community/cli-tools/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@react-native-community/cli-tools/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@react-native-community/cli-tools/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@react-native-community/cli-tools/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@react-native-community/cli-types": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-12.3.7.tgz", + "integrity": "sha512-NFtUMyIrNfi3A5C1cjVKDVvYHvvOF7MnOMwdD8jm2NQKewQJrehKBh1eMuykKdqhWyZmuemD4KKhL8f4FxgG0w==", + "license": "MIT", + "dependencies": { + "joi": "^17.2.1" + } + }, + "node_modules/@react-native-community/cli/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@react-native-community/cli/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@react-native-community/cli/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@react-native-community/cli/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/@react-native/assets-registry": { + "version": "0.73.1", + "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.73.1.tgz", + "integrity": "sha512-2FgAbU7uKM5SbbW9QptPPZx8N9Ke2L7bsHb+EhAanZjFZunA9PaYtyjUQ1s7HD+zDVqOQIvjkpXSv7Kejd2tqg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/babel-plugin-codegen": { + "version": "0.73.4", + "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.73.4.tgz", + "integrity": "sha512-XzRd8MJGo4Zc5KsphDHBYJzS1ryOHg8I2gOZDAUCGcwLFhdyGu1zBNDJYH2GFyDrInn9TzAbRIf3d4O+eltXQQ==", + "license": "MIT", + "dependencies": { + "@react-native/codegen": "0.73.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/babel-preset": { + "version": "0.73.21", + "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.73.21.tgz", + "integrity": "sha512-WlFttNnySKQMeujN09fRmrdWqh46QyJluM5jdtDNrkl/2Hx6N4XeDUGhABvConeK95OidVO7sFFf7sNebVXogA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.20.0", + "@babel/plugin-proposal-async-generator-functions": "^7.0.0", + "@babel/plugin-proposal-class-properties": "^7.18.0", + "@babel/plugin-proposal-export-default-from": "^7.0.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.0", + "@babel/plugin-proposal-numeric-separator": "^7.0.0", + "@babel/plugin-proposal-object-rest-spread": "^7.20.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.0.0", + "@babel/plugin-proposal-optional-chaining": "^7.20.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-export-default-from": "^7.0.0", + "@babel/plugin-syntax-flow": "^7.18.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0", + "@babel/plugin-syntax-optional-chaining": "^7.0.0", + "@babel/plugin-transform-arrow-functions": "^7.0.0", + "@babel/plugin-transform-async-to-generator": "^7.20.0", + "@babel/plugin-transform-block-scoping": "^7.0.0", + "@babel/plugin-transform-classes": "^7.0.0", + "@babel/plugin-transform-computed-properties": "^7.0.0", + "@babel/plugin-transform-destructuring": "^7.20.0", + "@babel/plugin-transform-flow-strip-types": "^7.20.0", + "@babel/plugin-transform-function-name": "^7.0.0", + "@babel/plugin-transform-literals": "^7.0.0", + "@babel/plugin-transform-modules-commonjs": "^7.0.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.0.0", + "@babel/plugin-transform-parameters": "^7.0.0", + "@babel/plugin-transform-private-methods": "^7.22.5", + "@babel/plugin-transform-private-property-in-object": "^7.22.11", + "@babel/plugin-transform-react-display-name": "^7.0.0", + "@babel/plugin-transform-react-jsx": "^7.0.0", + "@babel/plugin-transform-react-jsx-self": "^7.0.0", + "@babel/plugin-transform-react-jsx-source": "^7.0.0", + "@babel/plugin-transform-runtime": "^7.0.0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0", + "@babel/plugin-transform-spread": "^7.0.0", + "@babel/plugin-transform-sticky-regex": "^7.0.0", + "@babel/plugin-transform-typescript": "^7.5.0", + "@babel/plugin-transform-unicode-regex": "^7.0.0", + "@babel/template": "^7.0.0", + "@react-native/babel-plugin-codegen": "0.73.4", + "babel-plugin-transform-flow-enums": "^0.0.2", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@react-native/babel-preset/node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@react-native/codegen": { + "version": "0.73.3", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.73.3.tgz", + "integrity": "sha512-sxslCAAb8kM06vGy9Jyh4TtvjhcP36k/rvj2QE2Jdhdm61KvfafCATSIsOfc0QvnduWFcpXUPvAVyYwuv7PYDg==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.0", + "flow-parser": "^0.206.0", + "glob": "^7.1.1", + "invariant": "^2.2.4", + "jscodeshift": "^0.14.0", + "mkdirp": "^0.5.1", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@babel/preset-env": "^7.1.6" + } + }, + "node_modules/@react-native/community-cli-plugin": { + "version": "0.73.18", + "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.73.18.tgz", + "integrity": "sha512-RN8piDh/eF+QT6YYmrj3Zd9uiaDsRY/kMT0FYR42j8/M/boE4hs4Xn0u91XzT8CAkU9q/ilyo3wJsXIJo2teww==", + "license": "MIT", + "dependencies": { + "@react-native-community/cli-server-api": "12.3.7", + "@react-native-community/cli-tools": "12.3.7", + "@react-native/dev-middleware": "0.73.8", + "@react-native/metro-babel-transformer": "0.73.15", + "chalk": "^4.0.0", + "execa": "^5.1.1", + "metro": "^0.80.3", + "metro-config": "^0.80.3", + "metro-core": "^0.80.3", + "node-fetch": "^2.2.0", + "readline": "^1.3.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/debugger-frontend": { + "version": "0.73.3", + "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.73.3.tgz", + "integrity": "sha512-RgEKnWuoo54dh7gQhV7kvzKhXZEhpF9LlMdZolyhGxHsBqZ2gXdibfDlfcARFFifPIiaZ3lXuOVVa4ei+uPgTw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/dev-middleware": { + "version": "0.73.8", + "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.73.8.tgz", + "integrity": "sha512-oph4NamCIxkMfUL/fYtSsE+JbGOnrlawfQ0kKtDQ5xbOjPKotKoXqrs1eGwozNKv7FfQ393stk1by9a6DyASSg==", + "license": "MIT", + "dependencies": { + "@isaacs/ttlcache": "^1.4.1", + "@react-native/debugger-frontend": "0.73.3", + "chrome-launcher": "^0.15.2", + "chromium-edge-launcher": "^1.0.0", + "connect": "^3.6.5", + "debug": "^2.2.0", + "node-fetch": "^2.2.0", + "open": "^7.0.3", + "serve-static": "^1.13.1", + "temp-dir": "^2.0.0", + "ws": "^6.2.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/dev-middleware/node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@react-native/dev-middleware/node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@react-native/dev-middleware/node_modules/ws": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", + "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", + "license": "MIT", + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/@react-native/eslint-config": { + "version": "0.73.2", + "resolved": "https://registry.npmjs.org/@react-native/eslint-config/-/eslint-config-0.73.2.tgz", + "integrity": "sha512-YzMfes19loTfbrkbYNAfHBDXX4oRBzc5wnvHs4h2GIHUj6YKs5ZK5lldqSrBJCdZAI3nuaO9Qj+t5JRwou571w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.20.0", + "@babel/eslint-parser": "^7.20.0", + "@react-native/eslint-plugin": "0.73.1", + "@typescript-eslint/eslint-plugin": "^5.57.1", + "@typescript-eslint/parser": "^5.57.1", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-ft-flow": "^2.0.1", + "eslint-plugin-jest": "^26.5.3", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-react": "^7.30.1", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-native": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": ">=8", + "prettier": ">=2" + } + }, + "node_modules/@react-native/eslint-plugin": { + "version": "0.73.1", + "resolved": "https://registry.npmjs.org/@react-native/eslint-plugin/-/eslint-plugin-0.73.1.tgz", + "integrity": "sha512-8BNMFE8CAI7JLWLOs3u33wcwcJ821LYs5g53Xyx9GhSg0h8AygTwDrwmYb/pp04FkCNCPjKPBoaYRthQZmxgwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/gradle-plugin": { + "version": "0.73.5", + "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.73.5.tgz", + "integrity": "sha512-Orrn8J/kqzEuXudl96XcZk84ZcdIpn1ojjwGSuaSQSXNcCYbOXyt0RwtW5kjCqjgSzGnOMsJNZc5FDXHVq/WzA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/js-polyfills": { + "version": "0.73.1", + "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.73.1.tgz", + "integrity": "sha512-ewMwGcumrilnF87H4jjrnvGZEaPFCAC4ebraEK+CurDDmwST/bIicI4hrOAv+0Z0F7DEK4O4H7r8q9vH7IbN4g==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/metro-babel-transformer": { + "version": "0.73.15", + "resolved": "https://registry.npmjs.org/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.73.15.tgz", + "integrity": "sha512-LlkSGaXCz+xdxc9819plmpsl4P4gZndoFtpjN3GMBIu6f7TBV0GVbyJAU4GE8fuAWPVSVL5ArOcdkWKSbI1klw==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.20.0", + "@react-native/babel-preset": "0.73.21", + "hermes-parser": "0.15.0", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@react-native/metro-config": { + "version": "0.73.5", + "resolved": "https://registry.npmjs.org/@react-native/metro-config/-/metro-config-0.73.5.tgz", + "integrity": "sha512-3bNWoHzOzP/+qoLJtRhOVXrnxKmSY3i4y5PXyMQlIvvOI/GQbXulPpEZxK/yUrf1MmeXHLLFufFbQWlfDEDoxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native/js-polyfills": "0.73.1", + "@react-native/metro-babel-transformer": "0.73.15", + "metro-config": "^0.80.3", + "metro-runtime": "^0.80.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/normalize-colors": { + "version": "0.73.2", + "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.73.2.tgz", + "integrity": "sha512-bRBcb2T+I88aG74LMVHaKms2p/T8aQd8+BZ7LuuzXlRfog1bMWWn/C5i0HVuvW4RPtXQYgIlGiXVDy9Ir1So/w==", + "license": "MIT" + }, + "node_modules/@react-native/typescript-config": { + "version": "0.73.1", + "resolved": "https://registry.npmjs.org/@react-native/typescript-config/-/typescript-config-0.73.1.tgz", + "integrity": "sha512-7Wrmdp972ZO7xvDid+xRGtvX6xz47cpGj7Y7VKlUhSVFFqbOGfB5WCpY1vMr6R/fjl+Og2fRw+TETN2+JnJi0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@react-native/virtualized-lists": { + "version": "0.73.4", + "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.73.4.tgz", + "integrity": "sha512-HpmLg1FrEiDtrtAbXiwCgXFYyloK/dOIPIuWW3fsqukwJEWAiTzm1nXGJ7xPU5XTHiWZ4sKup5Ebaj8z7iyWog==", + "license": "MIT", + "dependencies": { + "invariant": "^2.2.4", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react-native": "*" + } + }, + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "license": "BSD-3-Clause" + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "2.0.0", + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.0.2", + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^2.0.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.18.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "18.0.0", + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.14", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", + "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz", + "integrity": "sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-test-renderer": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-18.3.1.tgz", + "integrity": "sha512-vAhnk0tG2eGa37lkU9+s5SoroCsRI08xnsWFiAXOuPH2jqzMbcXvKExXViPi1P5fIklDeCvXqyrdmipFaSkZrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "^18" + } + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.24", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/anser": { + "version": "1.4.10", + "license": "MIT" + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-fragments": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ansi-fragments/-/ansi-fragments-0.2.1.tgz", + "integrity": "sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w==", + "license": "MIT", + "dependencies": { + "colorette": "^1.0.7", + "slice-ansi": "^2.0.0", + "strip-ansi": "^5.0.0" + } + }, + "node_modules/ansi-fragments/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-fragments/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/appdirsjs": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/appdirsjs/-/appdirsjs-1.2.7.tgz", + "integrity": "sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "1.0.10", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "license": "MIT" + }, + "node_modules/ast-types": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.15.2.tgz", + "integrity": "sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/async-limiter": { + "version": "1.0.1", + "license": "MIT" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/babel-core": { + "version": "7.0.0-bridge.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", + "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", + "license": "MIT", + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.3.1", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.13.11", + "@babel/helper-define-polyfill-provider": "^0.3.1", + "semver": "^6.1.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.5.2", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.1", + "core-js-compat": "^3.21.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.3.1", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-transform-flow-enums": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-enums/-/babel-plugin-transform-flow-enums-0.0.2.tgz", + "integrity": "sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==", + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-flow": "^7.12.1" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", + "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/base-64": { + "version": "0.1.0" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/browserslist": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "license": "MIT" + }, + "node_modules/bunyan": { + "version": "1.8.15", + "dev": true, + "engines": [ + "node >=0.10.0" + ], + "license": "MIT", + "bin": { + "bunyan": "bin/bunyan" + }, + "optionalDependencies": { + "dtrace-provider": "~0.8", + "moment": "^2.19.3", + "mv": "~2", + "safe-json-stringify": "~1" + } + }, + "node_modules/bunyan-debug-stream": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2" + }, + "engines": { + "node": ">=0.12.0" + }, + "peerDependencies": { + "bunyan": "*" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/caf": { + "version": "15.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", + "license": "MIT", + "dependencies": { + "callsites": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/caller-callsite/node_modules/callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", + "license": "MIT", + "dependencies": { + "caller-callsite": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001660", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001660.tgz", + "integrity": "sha512-GacvNTTuATm26qC74pt+ad1fW15mlQ/zuTzzY1ZoIzECTP8HURDfF43kNxPgf7H1jmelCBQTTbBNxdSXOA7Bqg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/child-process-promise": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^4.0.2", + "node-version": "^1.0.0", + "promise-polyfill": "^6.0.1" + } + }, + "node_modules/child-process-promise/node_modules/cross-spawn": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "node_modules/child-process-promise/node_modules/lru-cache": { + "version": "4.1.5", + "dev": true, + "license": "ISC", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/child-process-promise/node_modules/yallist": { + "version": "2.1.2", + "dev": true, + "license": "ISC" + }, + "node_modules/chrome-launcher": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz", + "integrity": "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0" + }, + "bin": { + "print-chrome-path": "bin/print-chrome-path.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/chrome-launcher/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chromium-edge-launcher": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-1.0.0.tgz", + "integrity": "sha512-pgtgjNKZ7i5U++1g1PWv75umkHvhVTDOQIZ+sjeUX9483S7Y6MUvO0lrd7ShGlQlFHMN4SwKTCq/X8hWrbv2KA==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0", + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "node_modules/chromium-edge-launcher/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chromium-edge-launcher/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.3.2", + "license": "MIT" + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "license": "MIT" + }, + "node_modules/colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "license": "MIT" + }, + "node_modules/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "license": "MIT" + }, + "node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "license": "MIT" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz", + "integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.0.2", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "license": "MIT" + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/core-js-compat": { + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.1.tgz", + "integrity": "sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "license": "MIT", + "dependencies": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cosmiconfig/node_modules/import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", + "license": "MIT", + "dependencies": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cosmiconfig/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cosmiconfig/node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dedent": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/denodeify": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz", + "integrity": "sha512-KNTihKNmQENUZeKu5fzfpzRqR5S2VMp4gl9RFHiWzj9DfvYQPMJ6XHKNaQxaGCXwPk6y9yme3aUoaiAe+KX+vg==", + "license": "MIT" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/deprecated-react-native-prop-types": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-5.0.0.tgz", + "integrity": "sha512-cIK8KYiiGVOFsKdPMmm1L3tA/Gl+JopXL6F5+C7x39MyPsQYnP57Im/D6bNUzcborD7fcMwiwZqcBdBXXZucYQ==", + "license": "MIT", + "dependencies": { + "@react-native/normalize-colors": "^0.73.0", + "invariant": "^2.2.4", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/detox": { + "version": "20.10.0", + "resolved": "https://registry.npmjs.org/detox/-/detox-20.10.0.tgz", + "integrity": "sha512-c6dCD5xTmiuOklbx4ptnXuznCnK4IMd9ZtB8jXxNJBqZpUXzqhmCniwKPZNwkdtye/xXbEFz4t5JWQKsVJ3z5Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.6.3", + "bunyan": "^1.8.12", + "bunyan-debug-stream": "^3.1.0", + "caf": "^15.0.1", + "chalk": "^4.0.0", + "child-process-promise": "^2.2.0", + "execa": "^5.1.1", + "find-up": "^5.0.0", + "fs-extra": "^11.0.0", + "funpermaproxy": "^1.1.0", + "glob": "^8.0.3", + "ini": "^1.3.4", + "json-cycle": "^1.3.0", + "lodash": "^4.17.11", + "multi-sort-stream": "^1.0.3", + "multipipe": "^4.0.0", + "node-ipc": "9.2.1", + "proper-lockfile": "^3.0.2", + "resolve-from": "^5.0.0", + "sanitize-filename": "^1.6.1", + "semver": "^7.0.0", + "serialize-error": "^8.0.1", + "shell-quote": "^1.7.2", + "signal-exit": "^3.0.3", + "stream-json": "^1.7.4", + "strip-ansi": "^6.0.1", + "telnet-client": "1.2.8", + "tempfile": "^2.0.0", + "trace-event-lib": "^1.3.1", + "which": "^1.3.1", + "ws": "^7.0.0", + "yargs": "^17.0.0", + "yargs-parser": "^21.0.0", + "yargs-unparser": "^2.0.0" + }, + "bin": { + "detox": "local-cli/cli.js" + }, + "engines": { + "node": ">=14.5.0" + }, + "peerDependencies": { + "jest": "29.x.x || 28.x.x || ^27.2.5" + }, + "peerDependenciesMeta": { + "jest": { + "optional": true + } + } + }, + "node_modules/detox/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/detox/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/detox/node_modules/glob": { + "version": "8.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/detox/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/detox/node_modules/minimatch": { + "version": "5.1.6", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/detox/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/detox/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/detox/node_modules/semver": { + "version": "7.5.4", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dtrace-provider": { + "version": "0.8.8", + "dev": true, + "hasInstallScript": true, + "license": "BSD-2-Clause", + "optional": true, + "dependencies": { + "nan": "^2.14.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/easy-stack": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.24", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.24.tgz", + "integrity": "sha512-0x0wLCmpdKFCi9ulhvYZebgcPmHTkFVUfU2wzDykadkslKwT4oAmDTHEKLnlrDsMGZe4B+ksn8quZfZjYsBetA==", + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/envinfo": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", + "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "license": "MIT", + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/errorhandler": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.5.1.tgz", + "integrity": "sha512-rcOwbfvP1WTViVoUjcfZicVzjhjTuhSMntHh6mW3IrEiyE6mJyXvsToJUJGlGlw/2xU9P5whlWNGlIDVeCiT4A==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.7", + "escape-html": "~1.0.3" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-abstract": { + "version": "1.23.9", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", + "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.0", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-regex": "^1.2.1", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.0", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.3", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.18" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", + "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.6", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.4", + "safe-array-concat": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", + "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-eslint-comments": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz", + "integrity": "sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5", + "ignore": "^5.0.5" + }, + "engines": { + "node": ">=6.5.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" + } + }, + "node_modules/eslint-plugin-ft-flow": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-ft-flow/-/eslint-plugin-ft-flow-2.0.3.tgz", + "integrity": "sha512-Vbsd/b+LYA99jUbsL6viEUWShFaYQt2YQs3QN3f+aeszOhh2sgdcU0mjzDyD4yyBvMc8qy2uwvBBWfMzEX06tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21", + "string-natural-compare": "^3.0.1" + }, + "engines": { + "node": ">=12.22.0" + }, + "peerDependencies": { + "@babel/eslint-parser": "^7.12.0", + "eslint": "^8.1.0" + } + }, + "node_modules/eslint-plugin-jest": { + "version": "26.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-26.9.0.tgz", + "integrity": "sha512-TWJxWGp1J628gxh2KhaH1H1paEdgE2J61BBF1I59c6xWeL5+D1BzMxGDN/nXAfX+aSkR5u80K+XhskK6Gwq9ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^5.10.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": ">=7.28.0", + "prettier": ">=2.0.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.37.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz", + "integrity": "sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", + "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react-native": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-native/-/eslint-plugin-react-native-4.1.0.tgz", + "integrity": "sha512-QLo7rzTBOl43FvVqDdq5Ql9IoElIuTdjrz9SKAXCvULvBoRZ44JGSkx9z4999ZusCsb4rK3gjS8gOGyeYqZv2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-plugin-react-native-globals": "^0.1.1" + }, + "peerDependencies": { + "eslint": "^3.17.0 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-native-globals": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz", + "integrity": "sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-pubsub": { + "version": "4.3.0", + "dev": true, + "license": "Unlicense", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "license": "Apache-2.0" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-xml-parser": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.3.tgz", + "integrity": "sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "strnum": "^1.1.1" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.1", + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "license": "MIT", + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "license": "MIT", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up/node_modules/path-exists": { + "version": "4.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/flow-enums-runtime": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz", + "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==", + "license": "MIT" + }, + "node_modules/flow-parser": { + "version": "0.206.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.206.0.tgz", + "integrity": "sha512-HVzoK3r6Vsg+lKvlIZzaWNBVai+FXTX1wdYhz/wVlH13tb/gOdLXmlTqy6odmTBhT5UoWUbq0k8263Qhr9d88w==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", + "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/funpermaproxy": { + "version": "1.1.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hermes-estree": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.15.0.tgz", + "integrity": "sha512-lLYvAd+6BnOqWdnNbP/Q8xfl8LOGw4wVjfrNd9Gt8eoFzhNBRVD95n4l2ksfMVOoxuVyegs85g83KS9QOsxbVQ==", + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.15.0.tgz", + "integrity": "sha512-Q1uks5rjZlE9RjMMjSUCkGrEIPI5pKJILeCtK1VmTj7U4pf3wVPoo+cxfu+s4cBAPy2JzikIIdCZgBoR6x7U1Q==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.15.0" + } + }, + "node_modules/hermes-profile-transformer": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/hermes-profile-transformer/-/hermes-profile-transformer-0.0.6.tgz", + "integrity": "sha512-cnN7bQUm65UWOy6cbGcCcZ3rpwW8Q/j4OP5aWRhEry4Z2t2aR1cjrbp0BS+KiBN0smvP1caBgAuxutvyvJILzQ==", + "license": "MIT", + "dependencies": { + "source-map": "^0.7.3" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/hermes-profile-transformer/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-size": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz", + "integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==", + "license": "MIT", + "dependencies": { + "queue": "6.0.2" + }, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=16.x" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "dev": true, + "license": "ISC" + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "license": "MIT" + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/joi": { + "version": "17.13.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", + "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, + "node_modules/js-message": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/js-queue": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "easy-stack": "^1.0.1" + }, + "engines": { + "node": ">=1.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsc-android": { + "version": "250231.0.0", + "resolved": "https://registry.npmjs.org/jsc-android/-/jsc-android-250231.0.0.tgz", + "integrity": "sha512-rS46PvsjYmdmuz1OAWXY/1kCYG7pnf1TBqeTiOJr1iDz7s5DLxxC9n/ZMknLDxzYzNVfI7R95MH10emSSG1Wuw==", + "license": "BSD-2-Clause" + }, + "node_modules/jsc-safe-url": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/jsc-safe-url/-/jsc-safe-url-0.2.4.tgz", + "integrity": "sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==", + "license": "0BSD" + }, + "node_modules/jscodeshift": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.14.0.tgz", + "integrity": "sha512-7eCC1knD7bLUPuSCwXsMZUH51O8jIcoVyKtI6P0XM0IVzlGjckPy3FIwQlorzbN0Sg79oK+RlohN32Mqf/lrYA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.13.16", + "@babel/parser": "^7.13.16", + "@babel/plugin-proposal-class-properties": "^7.13.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.8", + "@babel/plugin-proposal-optional-chaining": "^7.13.12", + "@babel/plugin-transform-modules-commonjs": "^7.13.8", + "@babel/preset-flow": "^7.13.13", + "@babel/preset-typescript": "^7.13.0", + "@babel/register": "^7.13.16", + "babel-core": "^7.0.0-bridge.0", + "chalk": "^4.1.2", + "flow-parser": "0.*", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.4", + "neo-async": "^2.5.0", + "node-dir": "^0.1.17", + "recast": "^0.21.0", + "temp": "^0.8.4", + "write-file-atomic": "^2.3.0" + }, + "bin": { + "jscodeshift": "bin/jscodeshift.js" + }, + "peerDependencies": { + "@babel/preset-env": "^7.1.6" + } + }, + "node_modules/jscodeshift/node_modules/write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-cycle": { + "version": "1.4.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lighthouse-logger": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz", + "integrity": "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==", + "license": "Apache-2.0", + "dependencies": { + "debug": "^2.6.9", + "marky": "^1.2.2" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/logkitty": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/logkitty/-/logkitty-0.7.1.tgz", + "integrity": "sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ==", + "license": "MIT", + "dependencies": { + "ansi-fragments": "^0.2.1", + "dayjs": "^1.8.15", + "yargs": "^15.1.0" + }, + "bin": { + "logkitty": "bin/logkitty.js" + } + }, + "node_modules/logkitty/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/logkitty/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/logkitty/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/logkitty/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "license": "ISC" + }, + "node_modules/logkitty/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/logkitty/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/marky": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.5.tgz", + "integrity": "sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==", + "license": "Apache-2.0" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/memoize-one": { + "version": "5.2.1", + "license": "MIT" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/metro": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.80.12.tgz", + "integrity": "sha512-1UsH5FzJd9quUsD1qY+zUG4JY3jo3YEMxbMYH9jT6NK3j4iORhlwTK8fYTfAUBhDKjgLfKjAh7aoazNE23oIRA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@babel/core": "^7.20.0", + "@babel/generator": "^7.20.0", + "@babel/parser": "^7.20.0", + "@babel/template": "^7.0.0", + "@babel/traverse": "^7.20.0", + "@babel/types": "^7.20.0", + "accepts": "^1.3.7", + "chalk": "^4.0.0", + "ci-info": "^2.0.0", + "connect": "^3.6.5", + "debug": "^2.2.0", + "denodeify": "^1.2.1", + "error-stack-parser": "^2.0.6", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "hermes-parser": "0.23.1", + "image-size": "^1.0.2", + "invariant": "^2.2.4", + "jest-worker": "^29.6.3", + "jsc-safe-url": "^0.2.2", + "lodash.throttle": "^4.1.1", + "metro-babel-transformer": "0.80.12", + "metro-cache": "0.80.12", + "metro-cache-key": "0.80.12", + "metro-config": "0.80.12", + "metro-core": "0.80.12", + "metro-file-map": "0.80.12", + "metro-resolver": "0.80.12", + "metro-runtime": "0.80.12", + "metro-source-map": "0.80.12", + "metro-symbolicate": "0.80.12", + "metro-transform-plugins": "0.80.12", + "metro-transform-worker": "0.80.12", + "mime-types": "^2.1.27", + "nullthrows": "^1.1.1", + "serialize-error": "^2.1.0", + "source-map": "^0.5.6", + "strip-ansi": "^6.0.0", + "throat": "^5.0.0", + "ws": "^7.5.10", + "yargs": "^17.6.2" + }, + "bin": { + "metro": "src/cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-babel-transformer": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.80.12.tgz", + "integrity": "sha512-YZziRs0MgA3pzCkkvOoQRXjIoVjvrpi/yRlJnObyIvMP6lFdtyG4nUGIwGY9VXnBvxmXD6mPY2e+NSw6JAyiRg==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.20.0", + "flow-enums-runtime": "^0.0.6", + "hermes-parser": "0.23.1", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-babel-transformer/node_modules/hermes-estree": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.23.1.tgz", + "integrity": "sha512-eT5MU3f5aVhTqsfIReZ6n41X5sYn4IdQL0nvz6yO+MMlPxw49aSARHLg/MSehQftyjnrE8X6bYregzSumqc6cg==", + "license": "MIT" + }, + "node_modules/metro-babel-transformer/node_modules/hermes-parser": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.23.1.tgz", + "integrity": "sha512-oxl5h2DkFW83hT4DAUJorpah8ou4yvmweUzLJmmr6YV2cezduCdlil1AvU/a/xSsAFo4WUcNA4GoV5Bvq6JffA==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.23.1" + } + }, + "node_modules/metro-cache": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.80.12.tgz", + "integrity": "sha512-p5kNHh2KJ0pbQI/H7ZBPCEwkyNcSz7OUkslzsiIWBMPQGFJ/xArMwkV7I+GJcWh+b4m6zbLxE5fk6fqbVK1xGA==", + "license": "MIT", + "dependencies": { + "exponential-backoff": "^3.1.1", + "flow-enums-runtime": "^0.0.6", + "metro-core": "0.80.12" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-cache-key": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.80.12.tgz", + "integrity": "sha512-o4BspKnugg/pE45ei0LGHVuBJXwRgruW7oSFAeSZvBKA/sGr0UhOGY3uycOgWInnS3v5yTTfiBA9lHlNRhsvGA==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-config": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.80.12.tgz", + "integrity": "sha512-4rwOWwrhm62LjB12ytiuR5NgK1ZBNr24/He8mqCsC+HXZ+ATbrewLNztzbAZHtFsrxP4D4GLTGgh96pCpYLSAQ==", + "license": "MIT", + "dependencies": { + "connect": "^3.6.5", + "cosmiconfig": "^5.0.5", + "flow-enums-runtime": "^0.0.6", + "jest-validate": "^29.6.3", + "metro": "0.80.12", + "metro-cache": "0.80.12", + "metro-core": "0.80.12", + "metro-runtime": "0.80.12" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-core": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.80.12.tgz", + "integrity": "sha512-QqdJ/yAK+IpPs2HU/h5v2pKEdANBagSsc6DRSjnwSyJsCoHlmyJKCaCJ7KhWGx+N4OHxh37hoA8fc2CuZbx0Fw==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "lodash.throttle": "^4.1.1", + "metro-resolver": "0.80.12" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-file-map": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.80.12.tgz", + "integrity": "sha512-sYdemWSlk66bWzW2wp79kcPMzwuG32x1ZF3otI0QZTmrnTaaTiGyhE66P1z6KR4n2Eu5QXiABa6EWbAQv0r8bw==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.0.3", + "debug": "^2.2.0", + "fb-watchman": "^2.0.0", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "invariant": "^2.2.4", + "jest-worker": "^29.6.3", + "micromatch": "^4.0.4", + "node-abort-controller": "^3.1.1", + "nullthrows": "^1.1.1", + "walker": "^1.0.7" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/metro-minify-terser": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.80.12.tgz", + "integrity": "sha512-muWzUw3y5k+9083ZoX9VaJLWEV2Jcgi+Oan0Mmb/fBNMPqP9xVDuy4pOMn/HOiGndgfh/MK7s4bsjkyLJKMnXQ==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "terser": "^5.15.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-resolver": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.80.12.tgz", + "integrity": "sha512-PR24gYRZnYHM3xT9pg6BdbrGbM/Cu1TcyIFBVlAk7qDAuHkUNQ1nMzWumWs+kwSvtd9eZGzHoucGJpTUEeLZAw==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-runtime": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.80.12.tgz", + "integrity": "sha512-LIx7+92p5rpI0i6iB4S4GBvvLxStNt6fF0oPMaUd1Weku7jZdfkCZzmrtDD9CSQ6EPb0T9NUZoyXIxlBa3wOCw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-source-map": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.80.12.tgz", + "integrity": "sha512-o+AXmE7hpvM8r8MKsx7TI21/eerYYy2DCDkWfoBkv+jNkl61khvDHlQn0cXZa6lrcNZiZkl9oHSMcwLLIrFmpw==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.20.0", + "@babel/types": "^7.20.0", + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-symbolicate": "0.80.12", + "nullthrows": "^1.1.1", + "ob1": "0.80.12", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-source-map/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/metro-symbolicate": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.80.12.tgz", + "integrity": "sha512-/dIpNdHksXkGHZXARZpL7doUzHqSNxgQ8+kQGxwpJuHnDhGkENxB5PS2QBaTDdEcmyTMjS53CN1rl9n1gR6fmw==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-source-map": "0.80.12", + "nullthrows": "^1.1.1", + "source-map": "^0.5.6", + "through2": "^2.0.1", + "vlq": "^1.0.0" + }, + "bin": { + "metro-symbolicate": "src/index.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-symbolicate/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/metro-transform-plugins": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.80.12.tgz", + "integrity": "sha512-WQWp00AcZvXuQdbjQbx1LzFR31IInlkCDYJNRs6gtEtAyhwpMMlL2KcHmdY+wjDO9RPcliZ+Xl1riOuBecVlPA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.20.0", + "@babel/generator": "^7.20.0", + "@babel/template": "^7.0.0", + "@babel/traverse": "^7.20.0", + "flow-enums-runtime": "^0.0.6", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-transform-worker": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.80.12.tgz", + "integrity": "sha512-KAPFN1y3eVqEbKLx1I8WOarHPqDMUa8WelWxaJCNKO/yHCP26zELeqTJvhsQup+8uwB6EYi/sp0b6TGoh6lOEA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.20.0", + "@babel/generator": "^7.20.0", + "@babel/parser": "^7.20.0", + "@babel/types": "^7.20.0", + "flow-enums-runtime": "^0.0.6", + "metro": "0.80.12", + "metro-babel-transformer": "0.80.12", + "metro-cache": "0.80.12", + "metro-cache-key": "0.80.12", + "metro-minify-terser": "0.80.12", + "metro-source-map": "0.80.12", + "metro-transform-plugins": "0.80.12", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro/node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "license": "MIT" + }, + "node_modules/metro/node_modules/hermes-estree": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.23.1.tgz", + "integrity": "sha512-eT5MU3f5aVhTqsfIReZ6n41X5sYn4IdQL0nvz6yO+MMlPxw49aSARHLg/MSehQftyjnrE8X6bYregzSumqc6cg==", + "license": "MIT" + }, + "node_modules/metro/node_modules/hermes-parser": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.23.1.tgz", + "integrity": "sha512-oxl5h2DkFW83hT4DAUJorpah8ou4yvmweUzLJmmr6YV2cezduCdlil1AvU/a/xSsAFo4WUcNA4GoV5Bvq6JffA==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.23.1" + } + }, + "node_modules/metro/node_modules/serialize-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/metro/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.53.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.53.0.tgz", + "integrity": "sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "license": "MIT" + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/moment": { + "version": "2.29.4", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/multi-sort-stream": { + "version": "1.0.4", + "dev": true, + "license": "bsd" + }, + "node_modules/multipipe": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "duplexer2": "^0.1.2", + "object-assign": "^4.1.0" + } + }, + "node_modules/mv": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "mkdirp": "~0.5.1", + "ncp": "~2.0.0", + "rimraf": "~2.4.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/mv/node_modules/glob": { + "version": "6.0.4", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mv/node_modules/rimraf": { + "version": "2.4.5", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "glob": "^6.0.1" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/nan": { + "version": "2.17.0", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true, + "license": "MIT" + }, + "node_modules/ncp": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "optional": true, + "bin": { + "ncp": "bin/ncp" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" + }, + "node_modules/nocache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/nocache/-/nocache-3.0.4.tgz", + "integrity": "sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "license": "MIT" + }, + "node_modules/node-dir": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", + "license": "MIT", + "dependencies": { + "minimatch": "^3.0.2" + }, + "engines": { + "node": ">= 0.10.5" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "license": "MIT" + }, + "node_modules/node-ipc": { + "version": "9.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "event-pubsub": "4.3.0", + "js-message": "1.0.7", + "js-queue": "2.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "license": "MIT" + }, + "node_modules/node-stream-zip": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.15.0.tgz", + "integrity": "sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/antelle" + } + }, + "node_modules/node-version": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nullthrows": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", + "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", + "license": "MIT" + }, + "node_modules/ob1": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.80.12.tgz", + "integrity": "sha512-VMArClVT6LkhUGpnuEoBuyjG9rzUyEzg4PDkav6wK1cLhOK02gPCYFxoiB4mqVnrMhDpIzJcrGNAMVi9P+hXrw==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz", + "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", + "license": "MIT", + "dependencies": { + "is-wsl": "^1.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/open/node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "license": "MIT" + }, + "node_modules/promise": { + "version": "8.3.0", + "license": "MIT", + "dependencies": { + "asap": "~2.0.6" + } + }, + "node_modules/promise-polyfill": { + "version": "6.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/proper-lockfile": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.11", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "dev": true, + "license": "ISC" + }, + "node_modules/punycode": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "license": "MIT", + "dependencies": { + "inherits": "~2.0.3" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/react": { + "version": "18.2.0", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-devtools-core": { + "version": "4.28.5", + "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.28.5.tgz", + "integrity": "sha512-cq/o30z9W2Wb4rzBefjv5fBalHU0rJGZCHAkf/RHSBWSSYwh8PlQTqqOJmgIIbBtpj27T6FIPXeomIjZtCNVqA==", + "license": "MIT", + "dependencies": { + "shell-quote": "^1.6.1", + "ws": "^7" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "license": "MIT" + }, + "node_modules/react-native": { + "version": "0.73.11", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.73.11.tgz", + "integrity": "sha512-yvQIX+ZXOHMFnhmwZ1fBpRI/53k+iLN8DxVf24Fx4ABU63RGAYfyCZC0/3W+5OUVx4KSIZUv4Tv+/NGIieBOwg==", + "license": "MIT", + "dependencies": { + "@jest/create-cache-key-function": "^29.6.3", + "@react-native-community/cli": "12.3.7", + "@react-native-community/cli-platform-android": "12.3.7", + "@react-native-community/cli-platform-ios": "12.3.7", + "@react-native/assets-registry": "0.73.1", + "@react-native/codegen": "0.73.3", + "@react-native/community-cli-plugin": "0.73.18", + "@react-native/gradle-plugin": "0.73.5", + "@react-native/js-polyfills": "0.73.1", + "@react-native/normalize-colors": "0.73.2", + "@react-native/virtualized-lists": "0.73.4", + "abort-controller": "^3.0.0", + "anser": "^1.4.9", + "ansi-regex": "^5.0.0", + "base64-js": "^1.5.1", + "chalk": "^4.0.0", + "deprecated-react-native-prop-types": "^5.0.0", + "event-target-shim": "^5.0.1", + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "jest-environment-node": "^29.6.3", + "jsc-android": "^250231.0.0", + "memoize-one": "^5.0.0", + "metro-runtime": "^0.80.3", + "metro-source-map": "^0.80.3", + "mkdirp": "^0.5.1", + "nullthrows": "^1.1.1", + "pretty-format": "^26.5.2", + "promise": "^8.3.0", + "react-devtools-core": "^4.27.7", + "react-refresh": "^0.14.0", + "react-shallow-renderer": "^16.15.0", + "regenerator-runtime": "^0.13.2", + "scheduler": "0.24.0-canary-efb381bbf-20230505", + "stacktrace-parser": "^0.1.10", + "whatwg-fetch": "^3.0.0", + "ws": "^6.2.2", + "yargs": "^17.6.2" + }, + "bin": { + "react-native": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "18.2.0" + } + }, + "node_modules/react-native-fs": { + "version": "2.20.0", + "license": "MIT", + "dependencies": { + "base-64": "^0.1.0", + "utf8": "^3.0.0" + }, + "peerDependencies": { + "react-native": "*", + "react-native-windows": "*" + }, + "peerDependenciesMeta": { + "react-native-windows": { + "optional": true + } + } + }, + "node_modules/react-native/node_modules/@jest/types": { + "version": "26.6.2", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/react-native/node_modules/@types/yargs": { + "version": "15.0.14", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/react-native/node_modules/pretty-format": { + "version": "26.6.2", + "license": "MIT", + "dependencies": { + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/react-native/node_modules/react-is": { + "version": "17.0.2", + "license": "MIT" + }, + "node_modules/react-native/node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-native/node_modules/ws": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", + "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", + "license": "MIT", + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/react-shallow-renderer": { + "version": "16.15.0", + "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", + "integrity": "sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==", + "license": "MIT", + "dependencies": { + "object-assign": "^4.1.1", + "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-test-renderer": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-18.2.0.tgz", + "integrity": "sha512-JWD+aQ0lh2gvh4NM3bBM42Kx+XybOxCpgYK7F8ugAlpaTSnWsX+39Z4XkOykGZAHrjwwTZT3x3KxswVWxHPUqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "react-is": "^18.2.0", + "react-shallow-renderer": "^16.15.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-test-renderer/node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readline": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz", + "integrity": "sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==", + "license": "BSD" + }, + "node_modules/recast": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.21.5.tgz", + "integrity": "sha512-hjMmLaUXAm1hIuTqOdeYObMslq/q+Xff6QE3Y2P+uoHAg2nmVlLBps2hzh1UJDdMtDTMXOFewK6ky51JQIeECg==", + "license": "MIT", + "dependencies": { + "ast-types": "0.15.2", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "license": "MIT" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "license": "MIT", + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "license": "ISC" + }, + "node_modules/resolve": { + "version": "1.22.0", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "license": "MIT" + }, + "node_modules/safe-json-stringify": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sanitize-filename": { + "version": "1.6.3", + "dev": true, + "license": "WTFPL OR ISC", + "dependencies": { + "truncate-utf8-bytes": "^1.0.0" + } + }, + "node_modules/scheduler": { + "version": "0.24.0-canary-efb381bbf-20230505", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.24.0-canary-efb381bbf-20230505.tgz", + "integrity": "sha512-ABvovCDe/k9IluqSh4/ISoq8tIJnW8euVAWYt5j/bg6dRnqwQwiGO1F/V4AyK96NGF/FB04FhOUDuWj8IKfABA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-error": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-static/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "license": "MIT" + }, + "node_modules/stacktrace-parser": { + "version": "0.1.10", + "license": "MIT", + "dependencies": { + "type-fest": "^0.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/stacktrace-parser/node_modules/type-fest": { + "version": "0.7.1", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stream-chain": { + "version": "2.2.5", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stream-json": { + "version": "1.7.5", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "stream-chain": "^2.2.5" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-natural-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", + "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width": { + "version": "4.2.3", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strnum": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz", + "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/sudo-prompt": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/sudo-prompt/-/sudo-prompt-9.2.1.tgz", + "integrity": "sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/telnet-client": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "bluebird": "^3.5.4" + }, + "funding": { + "type": "paypal", + "url": "https://paypal.me/kozjak" + } + }, + "node_modules/temp": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz", + "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==", + "license": "MIT", + "dependencies": { + "rimraf": "~2.6.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/temp-dir": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/temp/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/tempfile": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "temp-dir": "^1.0.0", + "uuid": "^3.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/terser": { + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.33.0.tgz", + "integrity": "sha512-JuPVaB7s1gdFKPKTelwUyRq5Sid2A3Gko2S0PncwdBq7kN9Ti9HPWDQ06MPsEDGsZeVESjKEnyGy68quBk1w6g==", + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/terser/node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/throat": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", + "license": "MIT" + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/to-regex-range/node_modules/is-number": { + "version": "7.0.0", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/trace-event-lib": { + "version": "1.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "browser-process-hrtime": "^1.0.0", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/truncate-utf8-bytes": { + "version": "1.0.2", + "dev": true, + "license": "WTFPL", + "dependencies": { + "utf8-byte-length": "^1.0.1" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/utf8": { + "version": "3.0.0", + "license": "MIT" + }, + "node_modules/utf8-byte-length": { + "version": "1.0.4", + "dev": true, + "license": "WTFPL" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "3.4.0", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vlq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", + "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==", + "license": "MIT" + }, + "node_modules/walker": { + "version": "1.0.8", + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-fetch": { + "version": "3.6.2", + "license": "MIT" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "1.3.1", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "license": "ISC" + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", + "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser/node_modules/decamelize": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/js/react_native/e2e/package.json b/js/react_native/e2e/package.json index 6a5291b9930ec..794452eda7f31 100644 --- a/js/react_native/e2e/package.json +++ b/js/react_native/e2e/package.json @@ -6,35 +6,34 @@ "scripts": { "android": "react-native run-android", "ios": "react-native run-ios", - "start": "react-native start", "lint": "eslint .", + "start": "react-native start", "test": "jest" }, - "engines": { - "node": ">=16" - }, "dependencies": { "react": "^18.2.0", - "react-native": "^0.72.17", + "react-native": "^0.73.11", "react-native-fs": "^2.20.0" }, "devDependencies": { "@babel/core": "^7.20.0", "@babel/preset-env": "^7.20.0", "@babel/runtime": "^7.20.0", - "@react-native/eslint-config": "^0.72.2", - "@react-native/metro-config": "^0.72.12", - "@tsconfig/react-native": "^3.0.0", - "@types/jest": "^29.2.1", - "@types/react": "^18.0.24", + "@react-native/babel-preset": "0.73.21", + "@react-native/eslint-config": "^0.73.2", + "@react-native/metro-config": "^0.73.5", + "@react-native/typescript-config": "0.73.1", + "@types/react": "^18.2.6", "@types/react-test-renderer": "^18.0.0", - "babel-jest": "^29.2.1", - "babel-plugin-module-resolver": "^4.0.0", + "babel-jest": "^29.6.3", "detox": "20.10.0", - "jest": "^29.2.1", - "metro-react-native-babel-preset": "0.76.9", - "prettier": "^2.4.1", + "eslint": "^8.19.0", + "jest": "^29.6.3", + "prettier": "^2.8.8", "react-test-renderer": "18.2.0", - "typescript": "4.8.4" + "typescript": "5.0.4" + }, + "engines": { + "node": ">=18" } } diff --git a/js/react_native/e2e/src/App.tsx b/js/react_native/e2e/src/App.tsx index 8a76edabc613e..2d8d57b576991 100644 --- a/js/react_native/e2e/src/App.tsx +++ b/js/react_native/e2e/src/App.tsx @@ -44,7 +44,7 @@ export default class App extends React.PureComponent<{}, State> { // test creating session with path console.log('Creating with path'); const pathSession: InferenceSession = await InferenceSession.create(modelPath); - pathSession.release(); + void pathSession.release(); // and with bytes console.log('Creating with bytes'); @@ -100,7 +100,7 @@ export default class App extends React.PureComponent<{}, State> { } }; - render(): JSX.Element { + render(): React.JSX.Element { const { output, imagePath } = this.state; return ( diff --git a/js/react_native/e2e/yarn.lock b/js/react_native/e2e/yarn.lock deleted file mode 100644 index c764eec7950c2..0000000000000 --- a/js/react_native/e2e/yarn.lock +++ /dev/null @@ -1,6942 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@ampproject/remapping@^2.2.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" - integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== - dependencies: - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.24" - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.2": - version "7.26.2" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" - integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== - dependencies: - "@babel/helper-validator-identifier" "^7.25.9" - js-tokens "^4.0.0" - picocolors "^1.0.0" - -"@babel/compat-data@^7.20.5", "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.26.5": - version "7.26.5" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.5.tgz#df93ac37f4417854130e21d72c66ff3d4b897fc7" - integrity sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg== - -"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.13.16", "@babel/core@^7.20.0", "@babel/core@^7.23.9": - version "7.26.7" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.7.tgz#0439347a183b97534d52811144d763a17f9d2b24" - integrity sha512-SRijHmF0PSPgLIBYlWnG0hyeJLwXE2CgpsXaMOrtt2yp9/86ALw6oUlj9KYuZ0JN07T4eBMVIW4li/9S1j2BGA== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.26.2" - "@babel/generator" "^7.26.5" - "@babel/helper-compilation-targets" "^7.26.5" - "@babel/helper-module-transforms" "^7.26.0" - "@babel/helpers" "^7.26.7" - "@babel/parser" "^7.26.7" - "@babel/template" "^7.25.9" - "@babel/traverse" "^7.26.7" - "@babel/types" "^7.26.7" - convert-source-map "^2.0.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.3" - semver "^6.3.1" - -"@babel/eslint-parser@^7.20.0": - version "7.26.5" - resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.26.5.tgz#aa669f4d873f9cd617050cf3c40c19cd96307efb" - integrity sha512-Kkm8C8uxI842AwQADxl0GbcG1rupELYLShazYEZO/2DYjhyWXJIOUVOE3tBYm6JXzUCNJOZEzqc4rCW/jsEQYQ== - dependencies: - "@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1" - eslint-visitor-keys "^2.1.0" - semver "^6.3.1" - -"@babel/generator@^7.20.0", "@babel/generator@^7.26.5", "@babel/generator@^7.7.2": - version "7.26.5" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.5.tgz#e44d4ab3176bbcaf78a5725da5f1dc28802a9458" - integrity sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw== - dependencies: - "@babel/parser" "^7.26.5" - "@babel/types" "^7.26.5" - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" - jsesc "^3.0.2" - -"@babel/helper-annotate-as-pure@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz#d8eac4d2dc0d7b6e11fa6e535332e0d3184f06b4" - integrity sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g== - dependencies: - "@babel/types" "^7.25.9" - -"@babel/helper-compilation-targets@^7.20.7", "@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.25.9", "@babel/helper-compilation-targets@^7.26.5": - version "7.26.5" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz#75d92bb8d8d51301c0d49e52a65c9a7fe94514d8" - integrity sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA== - dependencies: - "@babel/compat-data" "^7.26.5" - "@babel/helper-validator-option" "^7.25.9" - browserslist "^4.24.0" - lru-cache "^5.1.1" - semver "^6.3.1" - -"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz#7644147706bb90ff613297d49ed5266bde729f83" - integrity sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.25.9" - "@babel/helper-member-expression-to-functions" "^7.25.9" - "@babel/helper-optimise-call-expression" "^7.25.9" - "@babel/helper-replace-supers" "^7.25.9" - "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" - "@babel/traverse" "^7.25.9" - semver "^6.3.1" - -"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.25.9": - version "7.26.3" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.26.3.tgz#5169756ecbe1d95f7866b90bb555b022595302a0" - integrity sha512-G7ZRb40uUgdKOQqPLjfD12ZmGA54PzqDFUv2BKImnC9QIfGhIHKvVML0oN8IUiDq4iRqpq74ABpvOaerfWdong== - dependencies: - "@babel/helper-annotate-as-pure" "^7.25.9" - regexpu-core "^6.2.0" - semver "^6.3.1" - -"@babel/helper-define-polyfill-provider@^0.6.2", "@babel/helper-define-polyfill-provider@^0.6.3": - version "0.6.3" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz#f4f2792fae2ef382074bc2d713522cf24e6ddb21" - integrity sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg== - dependencies: - "@babel/helper-compilation-targets" "^7.22.6" - "@babel/helper-plugin-utils" "^7.22.5" - debug "^4.1.1" - lodash.debounce "^4.0.8" - resolve "^1.14.2" - -"@babel/helper-environment-visitor@^7.18.9": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz#4b31ba9551d1f90781ba83491dd59cf9b269f7d9" - integrity sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ== - dependencies: - "@babel/types" "^7.24.7" - -"@babel/helper-member-expression-to-functions@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz#9dfffe46f727005a5ea29051ac835fb735e4c1a3" - integrity sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ== - dependencies: - "@babel/traverse" "^7.25.9" - "@babel/types" "^7.25.9" - -"@babel/helper-module-imports@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz#e7f8d20602ebdbf9ebbea0a0751fb0f2a4141715" - integrity sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw== - dependencies: - "@babel/traverse" "^7.25.9" - "@babel/types" "^7.25.9" - -"@babel/helper-module-transforms@^7.25.9", "@babel/helper-module-transforms@^7.26.0": - version "7.26.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz#8ce54ec9d592695e58d84cd884b7b5c6a2fdeeae" - integrity sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw== - dependencies: - "@babel/helper-module-imports" "^7.25.9" - "@babel/helper-validator-identifier" "^7.25.9" - "@babel/traverse" "^7.25.9" - -"@babel/helper-optimise-call-expression@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz#3324ae50bae7e2ab3c33f60c9a877b6a0146b54e" - integrity sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ== - dependencies: - "@babel/types" "^7.25.9" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.25.9", "@babel/helper-plugin-utils@^7.26.5", "@babel/helper-plugin-utils@^7.8.0": - version "7.26.5" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz#18580d00c9934117ad719392c4f6585c9333cc35" - integrity sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg== - -"@babel/helper-remap-async-to-generator@^7.18.9", "@babel/helper-remap-async-to-generator@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz#e53956ab3d5b9fb88be04b3e2f31b523afd34b92" - integrity sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.25.9" - "@babel/helper-wrap-function" "^7.25.9" - "@babel/traverse" "^7.25.9" - -"@babel/helper-replace-supers@^7.25.9": - version "7.26.5" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz#6cb04e82ae291dae8e72335dfe438b0725f14c8d" - integrity sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.25.9" - "@babel/helper-optimise-call-expression" "^7.25.9" - "@babel/traverse" "^7.26.5" - -"@babel/helper-skip-transparent-expression-wrappers@^7.20.0", "@babel/helper-skip-transparent-expression-wrappers@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz#0b2e1b62d560d6b1954893fd2b705dc17c91f0c9" - integrity sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA== - dependencies: - "@babel/traverse" "^7.25.9" - "@babel/types" "^7.25.9" - -"@babel/helper-string-parser@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c" - integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== - -"@babel/helper-validator-identifier@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" - integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== - -"@babel/helper-validator-option@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72" - integrity sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw== - -"@babel/helper-wrap-function@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz#d99dfd595312e6c894bd7d237470025c85eea9d0" - integrity sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g== - dependencies: - "@babel/template" "^7.25.9" - "@babel/traverse" "^7.25.9" - "@babel/types" "^7.25.9" - -"@babel/helpers@^7.26.7": - version "7.26.7" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.26.7.tgz#fd1d2a7c431b6e39290277aacfd8367857c576a4" - integrity sha512-8NHiL98vsi0mbPQmYAGWwfcFaOy4j2HY49fXJCfuDcdE7fMIsH9a7GdaeXpIBsbT7307WU8KCMp5pUVDNL4f9A== - dependencies: - "@babel/template" "^7.25.9" - "@babel/types" "^7.26.7" - -"@babel/parser@^7.1.0", "@babel/parser@^7.13.16", "@babel/parser@^7.14.7", "@babel/parser@^7.20.0", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.25.9", "@babel/parser@^7.26.5", "@babel/parser@^7.26.7": - version "7.26.7" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.7.tgz#e114cd099e5f7d17b05368678da0fb9f69b3385c" - integrity sha512-kEvgGGgEjRUutvdVvZhbn/BxVt+5VSpwXz1j3WYXQbXDo8KzFOPNG2GQbdAiNq8g6wn1yKk7C/qrke03a84V+w== - dependencies: - "@babel/types" "^7.26.7" - -"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz#cc2e53ebf0a0340777fff5ed521943e253b4d8fe" - integrity sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/traverse" "^7.25.9" - -"@babel/plugin-bugfix-safari-class-field-initializer-scope@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz#af9e4fb63ccb8abcb92375b2fcfe36b60c774d30" - integrity sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz#e8dc26fcd616e6c5bf2bd0d5a2c151d4f92a9137" - integrity sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz#807a667f9158acac6f6164b4beb85ad9ebc9e1d1" - integrity sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" - "@babel/plugin-transform-optional-chaining" "^7.25.9" - -"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz#de7093f1e7deaf68eadd7cc6b07f2ab82543269e" - integrity sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/traverse" "^7.25.9" - -"@babel/plugin-proposal-async-generator-functions@^7.0.0": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz#bfb7276d2d573cb67ba379984a2334e262ba5326" - integrity sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA== - dependencies: - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-remap-async-to-generator" "^7.18.9" - "@babel/plugin-syntax-async-generators" "^7.8.4" - -"@babel/plugin-proposal-class-properties@^7.0.0", "@babel/plugin-proposal-class-properties@^7.13.0", "@babel/plugin-proposal-class-properties@^7.18.0": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" - integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-proposal-export-default-from@^7.0.0": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.25.9.tgz#52702be6ef8367fc8f18b8438278332beeb8f87c" - integrity sha512-ykqgwNfSnNOB+C8fV5X4mG3AVmvu+WVxcaU9xHHtBb7PCrPeweMmPjGsn8eMaeJg6SJuoUuZENeeSWaarWqonQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-proposal-nullish-coalescing-operator@^7.13.8", "@babel/plugin-proposal-nullish-coalescing-operator@^7.18.0": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz#fdd940a99a740e577d6c753ab6fbb43fdb9467e1" - integrity sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - -"@babel/plugin-proposal-numeric-separator@^7.0.0": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz#899b14fbafe87f053d2c5ff05b36029c62e13c75" - integrity sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - -"@babel/plugin-proposal-object-rest-spread@^7.0.0", "@babel/plugin-proposal-object-rest-spread@^7.20.0": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz#aa662940ef425779c75534a5c41e9d936edc390a" - integrity sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg== - dependencies: - "@babel/compat-data" "^7.20.5" - "@babel/helper-compilation-targets" "^7.20.7" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.20.7" - -"@babel/plugin-proposal-optional-catch-binding@^7.0.0": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz#f9400d0e6a3ea93ba9ef70b09e72dd6da638a2cb" - integrity sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - -"@babel/plugin-proposal-optional-chaining@^7.13.12", "@babel/plugin-proposal-optional-chaining@^7.20.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz#886f5c8978deb7d30f678b2e24346b287234d3ea" - integrity sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - -"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": - version "7.21.0-placeholder-for-preset-env.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" - integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== - -"@babel/plugin-syntax-async-generators@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" - integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-bigint@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" - integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-class-properties@^7.0.0", "@babel/plugin-syntax-class-properties@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" - integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - -"@babel/plugin-syntax-class-static-block@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" - integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-dynamic-import@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" - integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-export-default-from@^7.0.0": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.25.9.tgz#86614767a9ff140366f0c3766ef218beb32a730a" - integrity sha512-9MhJ/SMTsVqsd69GyQg89lYR4o9T+oDGv5F6IsigxxqFVOyR/IflDLYP8WDI1l8fkhNGGktqkvL5qwNCtGEpgQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-syntax-flow@^7.0.0", "@babel/plugin-syntax-flow@^7.12.1", "@babel/plugin-syntax-flow@^7.18.0", "@babel/plugin-syntax-flow@^7.26.0": - version "7.26.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.26.0.tgz#96507595c21b45fccfc2bc758d5c45452e6164fa" - integrity sha512-B+O2DnPc0iG+YXFqOxv2WNuNU97ToWjOomUQ78DouOENWUaM5sVrmet9mcomUGQFwpJd//gvUagXBSdzO1fRKg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-syntax-import-assertions@^7.26.0": - version "7.26.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz#620412405058efa56e4a564903b79355020f445f" - integrity sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-syntax-import-attributes@^7.24.7", "@babel/plugin-syntax-import-attributes@^7.26.0": - version "7.26.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz#3b1412847699eea739b4f2602c74ce36f6b0b0f7" - integrity sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-syntax-import-meta@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" - integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-json-strings@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" - integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-jsx@^7.0.0", "@babel/plugin-syntax-jsx@^7.25.9", "@babel/plugin-syntax-jsx@^7.7.2": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz#a34313a178ea56f1951599b929c1ceacee719290" - integrity sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" - integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-nullish-coalescing-operator@^7.0.0", "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" - integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-numeric-separator@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" - integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" - integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-catch-binding@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" - integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-chaining@^7.0.0", "@babel/plugin-syntax-optional-chaining@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" - integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-private-property-in-object@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" - integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-top-level-await@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" - integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-typescript@^7.25.9", "@babel/plugin-syntax-typescript@^7.7.2": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz#67dda2b74da43727cf21d46cf9afef23f4365399" - integrity sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-syntax-unicode-sets-regex@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" - integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-arrow-functions@^7.0.0", "@babel/plugin-transform-arrow-functions@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz#7821d4410bee5daaadbb4cdd9a6649704e176845" - integrity sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-async-generator-functions@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz#1b18530b077d18a407c494eb3d1d72da505283a2" - integrity sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-remap-async-to-generator" "^7.25.9" - "@babel/traverse" "^7.25.9" - -"@babel/plugin-transform-async-to-generator@^7.20.0", "@babel/plugin-transform-async-to-generator@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz#c80008dacae51482793e5a9c08b39a5be7e12d71" - integrity sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ== - dependencies: - "@babel/helper-module-imports" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-remap-async-to-generator" "^7.25.9" - -"@babel/plugin-transform-block-scoped-functions@^7.0.0", "@babel/plugin-transform-block-scoped-functions@^7.26.5": - version "7.26.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.26.5.tgz#3dc4405d31ad1cbe45293aa57205a6e3b009d53e" - integrity sha512-chuTSY+hq09+/f5lMj8ZSYgCFpppV2CbYrhNFJ1BFoXpiWPnnAb7R0MqrafCpN8E1+YRrtM1MXZHJdIx8B6rMQ== - dependencies: - "@babel/helper-plugin-utils" "^7.26.5" - -"@babel/plugin-transform-block-scoping@^7.0.0", "@babel/plugin-transform-block-scoping@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz#c33665e46b06759c93687ca0f84395b80c0473a1" - integrity sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-class-properties@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz#a8ce84fedb9ad512549984101fa84080a9f5f51f" - integrity sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-class-static-block@^7.26.0": - version "7.26.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz#6c8da219f4eb15cae9834ec4348ff8e9e09664a0" - integrity sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-classes@^7.0.0", "@babel/plugin-transform-classes@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz#7152457f7880b593a63ade8a861e6e26a4469f52" - integrity sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.25.9" - "@babel/helper-compilation-targets" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-replace-supers" "^7.25.9" - "@babel/traverse" "^7.25.9" - globals "^11.1.0" - -"@babel/plugin-transform-computed-properties@^7.0.0", "@babel/plugin-transform-computed-properties@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz#db36492c78460e534b8852b1d5befe3c923ef10b" - integrity sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/template" "^7.25.9" - -"@babel/plugin-transform-destructuring@^7.0.0", "@babel/plugin-transform-destructuring@^7.20.0", "@babel/plugin-transform-destructuring@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz#966ea2595c498224340883602d3cfd7a0c79cea1" - integrity sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-dotall-regex@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz#bad7945dd07734ca52fe3ad4e872b40ed09bb09a" - integrity sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-duplicate-keys@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz#8850ddf57dce2aebb4394bb434a7598031059e6d" - integrity sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-duplicate-named-capturing-groups-regex@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz#6f7259b4de127721a08f1e5165b852fcaa696d31" - integrity sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-dynamic-import@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz#23e917de63ed23c6600c5dd06d94669dce79f7b8" - integrity sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-exponentiation-operator@^7.26.3": - version "7.26.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz#e29f01b6de302c7c2c794277a48f04a9ca7f03bc" - integrity sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-export-namespace-from@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz#90745fe55053394f554e40584cda81f2c8a402a2" - integrity sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-flow-strip-types@^7.0.0", "@babel/plugin-transform-flow-strip-types@^7.20.0", "@babel/plugin-transform-flow-strip-types@^7.25.9": - version "7.26.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.26.5.tgz#2904c85a814e7abb1f4850b8baf4f07d0a2389d4" - integrity sha512-eGK26RsbIkYUns3Y8qKl362juDDYK+wEdPGHGrhzUl6CewZFo55VZ7hg+CyMFU4dd5QQakBN86nBMpRsFpRvbQ== - dependencies: - "@babel/helper-plugin-utils" "^7.26.5" - "@babel/plugin-syntax-flow" "^7.26.0" - -"@babel/plugin-transform-for-of@^7.0.0", "@babel/plugin-transform-for-of@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz#4bdc7d42a213397905d89f02350c5267866d5755" - integrity sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" - -"@babel/plugin-transform-function-name@^7.0.0", "@babel/plugin-transform-function-name@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz#939d956e68a606661005bfd550c4fc2ef95f7b97" - integrity sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA== - dependencies: - "@babel/helper-compilation-targets" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/traverse" "^7.25.9" - -"@babel/plugin-transform-json-strings@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz#c86db407cb827cded902a90c707d2781aaa89660" - integrity sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-literals@^7.0.0", "@babel/plugin-transform-literals@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz#1a1c6b4d4aa59bc4cad5b6b3a223a0abd685c9de" - integrity sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-logical-assignment-operators@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz#b19441a8c39a2fda0902900b306ea05ae1055db7" - integrity sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-member-expression-literals@^7.0.0", "@babel/plugin-transform-member-expression-literals@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz#63dff19763ea64a31f5e6c20957e6a25e41ed5de" - integrity sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-modules-amd@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz#49ba478f2295101544abd794486cd3088dddb6c5" - integrity sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw== - dependencies: - "@babel/helper-module-transforms" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-modules-commonjs@^7.0.0", "@babel/plugin-transform-modules-commonjs@^7.13.8", "@babel/plugin-transform-modules-commonjs@^7.25.9", "@babel/plugin-transform-modules-commonjs@^7.26.3": - version "7.26.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz#8f011d44b20d02c3de44d8850d971d8497f981fb" - integrity sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ== - dependencies: - "@babel/helper-module-transforms" "^7.26.0" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-modules-systemjs@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz#8bd1b43836269e3d33307151a114bcf3ba6793f8" - integrity sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA== - dependencies: - "@babel/helper-module-transforms" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-validator-identifier" "^7.25.9" - "@babel/traverse" "^7.25.9" - -"@babel/plugin-transform-modules-umd@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz#6710079cdd7c694db36529a1e8411e49fcbf14c9" - integrity sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw== - dependencies: - "@babel/helper-module-transforms" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-named-capturing-groups-regex@^7.0.0", "@babel/plugin-transform-named-capturing-groups-regex@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz#454990ae6cc22fd2a0fa60b3a2c6f63a38064e6a" - integrity sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-new-target@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz#42e61711294b105c248336dcb04b77054ea8becd" - integrity sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-nullish-coalescing-operator@^7.26.6": - version "7.26.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.26.6.tgz#fbf6b3c92cb509e7b319ee46e3da89c5bedd31fe" - integrity sha512-CKW8Vu+uUZneQCPtXmSBUC6NCAUdya26hWCElAWh5mVSlSRsmiCPUUDKb3Z0szng1hiAJa098Hkhg9o4SE35Qw== - dependencies: - "@babel/helper-plugin-utils" "^7.26.5" - -"@babel/plugin-transform-numeric-separator@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz#bfed75866261a8b643468b0ccfd275f2033214a1" - integrity sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-object-rest-spread@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz#0203725025074164808bcf1a2cfa90c652c99f18" - integrity sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg== - dependencies: - "@babel/helper-compilation-targets" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/plugin-transform-parameters" "^7.25.9" - -"@babel/plugin-transform-object-super@^7.0.0", "@babel/plugin-transform-object-super@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz#385d5de135162933beb4a3d227a2b7e52bb4cf03" - integrity sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-replace-supers" "^7.25.9" - -"@babel/plugin-transform-optional-catch-binding@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz#10e70d96d52bb1f10c5caaac59ac545ea2ba7ff3" - integrity sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-optional-chaining@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz#e142eb899d26ef715435f201ab6e139541eee7dd" - integrity sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" - -"@babel/plugin-transform-parameters@^7.0.0", "@babel/plugin-transform-parameters@^7.20.7", "@babel/plugin-transform-parameters@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz#b856842205b3e77e18b7a7a1b94958069c7ba257" - integrity sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-private-methods@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz#847f4139263577526455d7d3223cd8bda51e3b57" - integrity sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-private-property-in-object@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz#9c8b73e64e6cc3cbb2743633885a7dd2c385fe33" - integrity sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.25.9" - "@babel/helper-create-class-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-property-literals@^7.0.0", "@babel/plugin-transform-property-literals@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz#d72d588bd88b0dec8b62e36f6fda91cedfe28e3f" - integrity sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-react-display-name@^7.0.0": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.9.tgz#4b79746b59efa1f38c8695065a92a9f5afb24f7d" - integrity sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-react-jsx-self@^7.0.0": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.9.tgz#c0b6cae9c1b73967f7f9eb2fca9536ba2fad2858" - integrity sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-react-jsx-source@^7.0.0": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.9.tgz#4c6b8daa520b5f155b5fb55547d7c9fa91417503" - integrity sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-react-jsx@^7.0.0": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz#06367940d8325b36edff5e2b9cbe782947ca4166" - integrity sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.25.9" - "@babel/helper-module-imports" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/plugin-syntax-jsx" "^7.25.9" - "@babel/types" "^7.25.9" - -"@babel/plugin-transform-regenerator@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz#03a8a4670d6cebae95305ac6defac81ece77740b" - integrity sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - regenerator-transform "^0.15.2" - -"@babel/plugin-transform-regexp-modifiers@^7.26.0": - version "7.26.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz#2f5837a5b5cd3842a919d8147e9903cc7455b850" - integrity sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-reserved-words@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz#0398aed2f1f10ba3f78a93db219b27ef417fb9ce" - integrity sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-runtime@^7.0.0": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.25.9.tgz#62723ea3f5b31ffbe676da9d6dae17138ae580ea" - integrity sha512-nZp7GlEl+yULJrClz0SwHPqir3lc0zsPrDHQUcxGspSL7AKrexNSEfTbfqnDNJUO13bgKyfuOLMF8Xqtu8j3YQ== - dependencies: - "@babel/helper-module-imports" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - babel-plugin-polyfill-corejs2 "^0.4.10" - babel-plugin-polyfill-corejs3 "^0.10.6" - babel-plugin-polyfill-regenerator "^0.6.1" - semver "^6.3.1" - -"@babel/plugin-transform-shorthand-properties@^7.0.0", "@babel/plugin-transform-shorthand-properties@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz#bb785e6091f99f826a95f9894fc16fde61c163f2" - integrity sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-spread@^7.0.0", "@babel/plugin-transform-spread@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz#24a35153931b4ba3d13cec4a7748c21ab5514ef9" - integrity sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" - -"@babel/plugin-transform-sticky-regex@^7.0.0", "@babel/plugin-transform-sticky-regex@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz#c7f02b944e986a417817b20ba2c504dfc1453d32" - integrity sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-template-literals@^7.0.0", "@babel/plugin-transform-template-literals@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz#6dbd4a24e8fad024df76d1fac6a03cf413f60fe1" - integrity sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-typeof-symbol@^7.26.7": - version "7.26.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.26.7.tgz#d0e33acd9223744c1e857dbd6fa17bd0a3786937" - integrity sha512-jfoTXXZTgGg36BmhqT3cAYK5qkmqvJpvNrPhaK/52Vgjhw4Rq29s9UqpWWV0D6yuRmgiFH/BUVlkl96zJWqnaw== - dependencies: - "@babel/helper-plugin-utils" "^7.26.5" - -"@babel/plugin-transform-typescript@^7.25.9", "@babel/plugin-transform-typescript@^7.5.0": - version "7.26.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.7.tgz#64339515ea3eff610160f62499c3ef437d0ac83d" - integrity sha512-5cJurntg+AT+cgelGP9Bt788DKiAw9gIMSMU2NJrLAilnj0m8WZWUNZPSLOmadYsujHutpgElO+50foX+ib/Wg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.25.9" - "@babel/helper-create-class-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.26.5" - "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" - "@babel/plugin-syntax-typescript" "^7.25.9" - -"@babel/plugin-transform-unicode-escapes@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz#a75ef3947ce15363fccaa38e2dd9bc70b2788b82" - integrity sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-unicode-property-regex@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz#a901e96f2c1d071b0d1bb5dc0d3c880ce8f53dd3" - integrity sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-unicode-regex@^7.0.0", "@babel/plugin-transform-unicode-regex@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz#5eae747fe39eacf13a8bd006a4fb0b5d1fa5e9b1" - integrity sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-unicode-sets-regex@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz#65114c17b4ffc20fa5b163c63c70c0d25621fabe" - integrity sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/preset-env@^7.20.0": - version "7.26.7" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.26.7.tgz#24d38e211f4570b8d806337035cc3ae798e0c36d" - integrity sha512-Ycg2tnXwixaXOVb29rana8HNPgLVBof8qqtNQ9LE22IoyZboQbGSxI6ZySMdW3K5nAe6gu35IaJefUJflhUFTQ== - dependencies: - "@babel/compat-data" "^7.26.5" - "@babel/helper-compilation-targets" "^7.26.5" - "@babel/helper-plugin-utils" "^7.26.5" - "@babel/helper-validator-option" "^7.25.9" - "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.25.9" - "@babel/plugin-bugfix-safari-class-field-initializer-scope" "^7.25.9" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.25.9" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.25.9" - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.25.9" - "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" - "@babel/plugin-syntax-import-assertions" "^7.26.0" - "@babel/plugin-syntax-import-attributes" "^7.26.0" - "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" - "@babel/plugin-transform-arrow-functions" "^7.25.9" - "@babel/plugin-transform-async-generator-functions" "^7.25.9" - "@babel/plugin-transform-async-to-generator" "^7.25.9" - "@babel/plugin-transform-block-scoped-functions" "^7.26.5" - "@babel/plugin-transform-block-scoping" "^7.25.9" - "@babel/plugin-transform-class-properties" "^7.25.9" - "@babel/plugin-transform-class-static-block" "^7.26.0" - "@babel/plugin-transform-classes" "^7.25.9" - "@babel/plugin-transform-computed-properties" "^7.25.9" - "@babel/plugin-transform-destructuring" "^7.25.9" - "@babel/plugin-transform-dotall-regex" "^7.25.9" - "@babel/plugin-transform-duplicate-keys" "^7.25.9" - "@babel/plugin-transform-duplicate-named-capturing-groups-regex" "^7.25.9" - "@babel/plugin-transform-dynamic-import" "^7.25.9" - "@babel/plugin-transform-exponentiation-operator" "^7.26.3" - "@babel/plugin-transform-export-namespace-from" "^7.25.9" - "@babel/plugin-transform-for-of" "^7.25.9" - "@babel/plugin-transform-function-name" "^7.25.9" - "@babel/plugin-transform-json-strings" "^7.25.9" - "@babel/plugin-transform-literals" "^7.25.9" - "@babel/plugin-transform-logical-assignment-operators" "^7.25.9" - "@babel/plugin-transform-member-expression-literals" "^7.25.9" - "@babel/plugin-transform-modules-amd" "^7.25.9" - "@babel/plugin-transform-modules-commonjs" "^7.26.3" - "@babel/plugin-transform-modules-systemjs" "^7.25.9" - "@babel/plugin-transform-modules-umd" "^7.25.9" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.25.9" - "@babel/plugin-transform-new-target" "^7.25.9" - "@babel/plugin-transform-nullish-coalescing-operator" "^7.26.6" - "@babel/plugin-transform-numeric-separator" "^7.25.9" - "@babel/plugin-transform-object-rest-spread" "^7.25.9" - "@babel/plugin-transform-object-super" "^7.25.9" - "@babel/plugin-transform-optional-catch-binding" "^7.25.9" - "@babel/plugin-transform-optional-chaining" "^7.25.9" - "@babel/plugin-transform-parameters" "^7.25.9" - "@babel/plugin-transform-private-methods" "^7.25.9" - "@babel/plugin-transform-private-property-in-object" "^7.25.9" - "@babel/plugin-transform-property-literals" "^7.25.9" - "@babel/plugin-transform-regenerator" "^7.25.9" - "@babel/plugin-transform-regexp-modifiers" "^7.26.0" - "@babel/plugin-transform-reserved-words" "^7.25.9" - "@babel/plugin-transform-shorthand-properties" "^7.25.9" - "@babel/plugin-transform-spread" "^7.25.9" - "@babel/plugin-transform-sticky-regex" "^7.25.9" - "@babel/plugin-transform-template-literals" "^7.25.9" - "@babel/plugin-transform-typeof-symbol" "^7.26.7" - "@babel/plugin-transform-unicode-escapes" "^7.25.9" - "@babel/plugin-transform-unicode-property-regex" "^7.25.9" - "@babel/plugin-transform-unicode-regex" "^7.25.9" - "@babel/plugin-transform-unicode-sets-regex" "^7.25.9" - "@babel/preset-modules" "0.1.6-no-external-plugins" - babel-plugin-polyfill-corejs2 "^0.4.10" - babel-plugin-polyfill-corejs3 "^0.10.6" - babel-plugin-polyfill-regenerator "^0.6.1" - core-js-compat "^3.38.1" - semver "^6.3.1" - -"@babel/preset-flow@^7.13.13": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.25.9.tgz#ef8b5e7e3f24a42b3711e77fb14919b87dffed0a" - integrity sha512-EASHsAhE+SSlEzJ4bzfusnXSHiU+JfAYzj+jbw2vgQKgq5HrUr8qs+vgtiEL5dOH6sEweI+PNt2D7AqrDSHyqQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-validator-option" "^7.25.9" - "@babel/plugin-transform-flow-strip-types" "^7.25.9" - -"@babel/preset-modules@0.1.6-no-external-plugins": - version "0.1.6-no-external-plugins" - resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz#ccb88a2c49c817236861fee7826080573b8a923a" - integrity sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/types" "^7.4.4" - esutils "^2.0.2" - -"@babel/preset-typescript@^7.13.0": - version "7.26.0" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.26.0.tgz#4a570f1b8d104a242d923957ffa1eaff142a106d" - integrity sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-validator-option" "^7.25.9" - "@babel/plugin-syntax-jsx" "^7.25.9" - "@babel/plugin-transform-modules-commonjs" "^7.25.9" - "@babel/plugin-transform-typescript" "^7.25.9" - -"@babel/register@^7.13.16": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.25.9.tgz#1c465acf7dc983d70ccc318eb5b887ecb04f021b" - integrity sha512-8D43jXtGsYmEeDvm4MWHYUpWf8iiXgWYx3fW7E7Wb7Oe6FWqJPl5K6TuFW0dOwNZzEE5rjlaSJYH9JjrUKJszA== - dependencies: - clone-deep "^4.0.1" - find-cache-dir "^2.0.0" - make-dir "^2.1.0" - pirates "^4.0.6" - source-map-support "^0.5.16" - -"@babel/runtime@^7.0.0", "@babel/runtime@^7.20.0", "@babel/runtime@^7.8.4": - version "7.26.7" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.7.tgz#f4e7fe527cd710f8dc0618610b61b4b060c3c341" - integrity sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ== - dependencies: - regenerator-runtime "^0.14.0" - -"@babel/template@^7.0.0", "@babel/template@^7.25.9", "@babel/template@^7.3.3": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.9.tgz#ecb62d81a8a6f5dc5fe8abfc3901fc52ddf15016" - integrity sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg== - dependencies: - "@babel/code-frame" "^7.25.9" - "@babel/parser" "^7.25.9" - "@babel/types" "^7.25.9" - -"@babel/traverse@^7.20.0", "@babel/traverse@^7.25.9", "@babel/traverse@^7.26.5", "@babel/traverse@^7.26.7": - version "7.26.7" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.7.tgz#99a0a136f6a75e7fb8b0a1ace421e0b25994b8bb" - integrity sha512-1x1sgeyRLC3r5fQOM0/xtQKsYjyxmFjaOrLJNtZ81inNjyJHGIolTULPiSc/2qe1/qfpFLisLQYFnnZl7QoedA== - dependencies: - "@babel/code-frame" "^7.26.2" - "@babel/generator" "^7.26.5" - "@babel/parser" "^7.26.7" - "@babel/template" "^7.25.9" - "@babel/types" "^7.26.7" - debug "^4.3.1" - globals "^11.1.0" - -"@babel/types@^7.0.0", "@babel/types@^7.20.0", "@babel/types@^7.20.7", "@babel/types@^7.24.7", "@babel/types@^7.25.9", "@babel/types@^7.26.5", "@babel/types@^7.26.7", "@babel/types@^7.3.3", "@babel/types@^7.4.4": - version "7.26.7" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.7.tgz#5e2b89c0768e874d4d061961f3a5a153d71dc17a" - integrity sha512-t8kDRGrKXyp6+tjUh7hw2RLyclsW4TRoRvRHtSyAX9Bb5ldlFh+90YAYY6awRXrlB4G5G2izNeGySpATlFzmOg== - dependencies: - "@babel/helper-string-parser" "^7.25.9" - "@babel/helper-validator-identifier" "^7.25.9" - -"@bcoe/v8-coverage@^0.2.3": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" - integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== - -"@eslint-community/eslint-utils@^4.2.0": - version "4.4.1" - resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz#d1145bf2c20132d6400495d6df4bf59362fd9d56" - integrity sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA== - dependencies: - eslint-visitor-keys "^3.4.3" - -"@eslint-community/regexpp@^4.4.0": - version "4.12.1" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" - integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== - -"@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0": - version "9.3.0" - resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb" - integrity sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ== - -"@hapi/topo@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012" - integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== - dependencies: - "@hapi/hoek" "^9.0.0" - -"@istanbuljs/load-nyc-config@^1.0.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" - integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== - dependencies: - camelcase "^5.3.1" - find-up "^4.1.0" - get-package-type "^0.1.0" - js-yaml "^3.13.1" - resolve-from "^5.0.0" - -"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" - integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== - -"@jest/console@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" - integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== - dependencies: - "@jest/types" "^29.6.3" - "@types/node" "*" - chalk "^4.0.0" - jest-message-util "^29.7.0" - jest-util "^29.7.0" - slash "^3.0.0" - -"@jest/core@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" - integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== - dependencies: - "@jest/console" "^29.7.0" - "@jest/reporters" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - ci-info "^3.2.0" - exit "^0.1.2" - graceful-fs "^4.2.9" - jest-changed-files "^29.7.0" - jest-config "^29.7.0" - jest-haste-map "^29.7.0" - jest-message-util "^29.7.0" - jest-regex-util "^29.6.3" - jest-resolve "^29.7.0" - jest-resolve-dependencies "^29.7.0" - jest-runner "^29.7.0" - jest-runtime "^29.7.0" - jest-snapshot "^29.7.0" - jest-util "^29.7.0" - jest-validate "^29.7.0" - jest-watcher "^29.7.0" - micromatch "^4.0.4" - pretty-format "^29.7.0" - slash "^3.0.0" - strip-ansi "^6.0.0" - -"@jest/create-cache-key-function@^29.2.1": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz#793be38148fab78e65f40ae30c36785f4ad859f0" - integrity sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA== - dependencies: - "@jest/types" "^29.6.3" - -"@jest/environment@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" - integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== - dependencies: - "@jest/fake-timers" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - jest-mock "^29.7.0" - -"@jest/expect-utils@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" - integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== - dependencies: - jest-get-type "^29.6.3" - -"@jest/expect@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" - integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== - dependencies: - expect "^29.7.0" - jest-snapshot "^29.7.0" - -"@jest/fake-timers@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" - integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== - dependencies: - "@jest/types" "^29.6.3" - "@sinonjs/fake-timers" "^10.0.2" - "@types/node" "*" - jest-message-util "^29.7.0" - jest-mock "^29.7.0" - jest-util "^29.7.0" - -"@jest/globals@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" - integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== - dependencies: - "@jest/environment" "^29.7.0" - "@jest/expect" "^29.7.0" - "@jest/types" "^29.6.3" - jest-mock "^29.7.0" - -"@jest/reporters@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" - integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== - dependencies: - "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" - "@jridgewell/trace-mapping" "^0.3.18" - "@types/node" "*" - chalk "^4.0.0" - collect-v8-coverage "^1.0.0" - exit "^0.1.2" - glob "^7.1.3" - graceful-fs "^4.2.9" - istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^6.0.0" - istanbul-lib-report "^3.0.0" - istanbul-lib-source-maps "^4.0.0" - istanbul-reports "^3.1.3" - jest-message-util "^29.7.0" - jest-util "^29.7.0" - jest-worker "^29.7.0" - slash "^3.0.0" - string-length "^4.0.1" - strip-ansi "^6.0.0" - v8-to-istanbul "^9.0.1" - -"@jest/schemas@^29.6.3": - version "29.6.3" - resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" - integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== - dependencies: - "@sinclair/typebox" "^0.27.8" - -"@jest/source-map@^29.6.3": - version "29.6.3" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" - integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== - dependencies: - "@jridgewell/trace-mapping" "^0.3.18" - callsites "^3.0.0" - graceful-fs "^4.2.9" - -"@jest/test-result@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" - integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== - dependencies: - "@jest/console" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/istanbul-lib-coverage" "^2.0.0" - collect-v8-coverage "^1.0.0" - -"@jest/test-sequencer@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" - integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== - dependencies: - "@jest/test-result" "^29.7.0" - graceful-fs "^4.2.9" - jest-haste-map "^29.7.0" - slash "^3.0.0" - -"@jest/transform@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" - integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== - dependencies: - "@babel/core" "^7.11.6" - "@jest/types" "^29.6.3" - "@jridgewell/trace-mapping" "^0.3.18" - babel-plugin-istanbul "^6.1.1" - chalk "^4.0.0" - convert-source-map "^2.0.0" - fast-json-stable-stringify "^2.1.0" - graceful-fs "^4.2.9" - jest-haste-map "^29.7.0" - jest-regex-util "^29.6.3" - jest-util "^29.7.0" - micromatch "^4.0.4" - pirates "^4.0.4" - slash "^3.0.0" - write-file-atomic "^4.0.2" - -"@jest/types@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" - integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^15.0.0" - chalk "^4.0.0" - -"@jest/types@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80" - integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^16.0.0" - chalk "^4.0.0" - -"@jest/types@^29.6.3": - version "29.6.3" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" - integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== - dependencies: - "@jest/schemas" "^29.6.3" - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^17.0.8" - chalk "^4.0.0" - -"@jridgewell/gen-mapping@^0.3.5": - version "0.3.8" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142" - integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA== - dependencies: - "@jridgewell/set-array" "^1.2.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.24" - -"@jridgewell/resolve-uri@^3.1.0": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" - integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== - -"@jridgewell/set-array@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" - integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== - -"@jridgewell/source-map@^0.3.3": - version "0.3.6" - resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a" - integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ== - dependencies: - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" - -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" - integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== - -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": - version "0.3.25" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" - integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - -"@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": - version "5.1.1-v1" - resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129" - integrity sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg== - dependencies: - eslint-scope "5.1.1" - -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.walk@^1.2.3": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - -"@react-native-community/cli-clean@11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-clean/-/cli-clean-11.4.1.tgz#0155a02e4158c8a61ba3d7a2b08f3ebebed81906" - integrity sha512-cwUbY3c70oBGv3FvQJWe2Qkq6m1+/dcEBonMDTYyH6i+6OrkzI4RkIGpWmbG1IS5JfE9ISUZkNL3946sxyWNkw== - dependencies: - "@react-native-community/cli-tools" "11.4.1" - chalk "^4.1.2" - execa "^5.0.0" - prompts "^2.4.0" - -"@react-native-community/cli-config@11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-config/-/cli-config-11.4.1.tgz#c27f91d2753f0f803cc79bbf299f19648a5d5627" - integrity sha512-sLdv1HFVqu5xNpeaR1+std0t7FFZaobpmpR0lFCOzKV7H/l611qS2Vo8zssmMK+oQbCs5JsX3SFPciODeIlaWA== - dependencies: - "@react-native-community/cli-tools" "11.4.1" - chalk "^4.1.2" - cosmiconfig "^5.1.0" - deepmerge "^4.3.0" - glob "^7.1.3" - joi "^17.2.1" - -"@react-native-community/cli-debugger-ui@11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-11.4.1.tgz#783cc276e1360baf8235dc8c6ebbbce0fe01d944" - integrity sha512-+pgIjGNW5TrJF37XG3djIOzP+WNoPp67to/ggDhrshuYgpymfb9XpDVsURJugy0Sy3RViqb83kQNK765QzTIvw== - dependencies: - serve-static "^1.13.1" - -"@react-native-community/cli-doctor@11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-doctor/-/cli-doctor-11.4.1.tgz#516ef5932de3e12989695e7cb7aba82b81e7b2de" - integrity sha512-O6oPiRsl8pdkcyNktpzvJAXUqdocoY4jh7Tt7wA69B1JKCJA7aPCecwJgpUZb63ZYoxOtRtYM3BYQKzRMLIuUw== - dependencies: - "@react-native-community/cli-config" "11.4.1" - "@react-native-community/cli-platform-android" "11.4.1" - "@react-native-community/cli-platform-ios" "11.4.1" - "@react-native-community/cli-tools" "11.4.1" - chalk "^4.1.2" - command-exists "^1.2.8" - envinfo "^7.7.2" - execa "^5.0.0" - hermes-profile-transformer "^0.0.6" - node-stream-zip "^1.9.1" - ora "^5.4.1" - prompts "^2.4.0" - semver "^7.5.2" - strip-ansi "^5.2.0" - sudo-prompt "^9.0.0" - wcwidth "^1.0.1" - yaml "^2.2.1" - -"@react-native-community/cli-hermes@11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-hermes/-/cli-hermes-11.4.1.tgz#abf487ae8ab53c66f6f1178bcd37ecbbbac9fb5c" - integrity sha512-1VAjwcmv+i9BJTMMVn5Grw7AcgURhTyfHVghJ1YgBE2euEJxPuqPKSxP54wBOQKnWUwsuDQAtQf+jPJoCxJSSA== - dependencies: - "@react-native-community/cli-platform-android" "11.4.1" - "@react-native-community/cli-tools" "11.4.1" - chalk "^4.1.2" - hermes-profile-transformer "^0.0.6" - -"@react-native-community/cli-platform-android@11.4.1", "@react-native-community/cli-platform-android@^11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-11.4.1.tgz#ec5fc97e87834f2e33cb0d34dcef6c17b20f60fc" - integrity sha512-VMmXWIzk0Dq5RAd+HIEa3Oe7xl2jso7+gOr6E2HALF4A3fCKUjKZQ6iK2t6AfnY04zftvaiKw6zUXtrfl52AVQ== - dependencies: - "@react-native-community/cli-tools" "11.4.1" - chalk "^4.1.2" - execa "^5.0.0" - glob "^7.1.3" - logkitty "^0.7.1" - -"@react-native-community/cli-platform-ios@11.4.1", "@react-native-community/cli-platform-ios@^11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-11.4.1.tgz#12d72741273b684734d5ed021415b7f543a6f009" - integrity sha512-RPhwn+q3IY9MpWc9w/Qmzv03mo8sXdah2eSZcECgweqD5SHWtOoRCUt11zM8jASpAQ8Tm5Je7YE9bHvdwGl4hA== - dependencies: - "@react-native-community/cli-tools" "11.4.1" - chalk "^4.1.2" - execa "^5.0.0" - fast-xml-parser "^4.0.12" - glob "^7.1.3" - ora "^5.4.1" - -"@react-native-community/cli-plugin-metro@11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-11.4.1.tgz#8d51c59a9a720f99150d4153e757d5d1d1dabd22" - integrity sha512-JxbIqknYcQ5Z4rWROtu5LNakLfMiKoWcMoPqIrBLrV5ILm1XUJj1/8fATCcotZqV3yzB3SCJ3RrhKx7dQ3YELw== - dependencies: - "@react-native-community/cli-server-api" "11.4.1" - "@react-native-community/cli-tools" "11.4.1" - chalk "^4.1.2" - execa "^5.0.0" - metro "^0.76.9" - metro-config "^0.76.9" - metro-core "^0.76.9" - metro-react-native-babel-transformer "^0.76.9" - metro-resolver "^0.76.9" - metro-runtime "^0.76.9" - readline "^1.3.0" - -"@react-native-community/cli-server-api@11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-server-api/-/cli-server-api-11.4.1.tgz#3dda094c4ab2369db34fe991c320e3cd78f097b3" - integrity sha512-isxXE8X5x+C4kN90yilD08jaLWD34hfqTfn/Xbl1u/igtdTsCaQGvWe9eaFamrpWFWTpVtj6k+vYfy8AtYSiKA== - dependencies: - "@react-native-community/cli-debugger-ui" "11.4.1" - "@react-native-community/cli-tools" "11.4.1" - compression "^1.7.1" - connect "^3.6.5" - errorhandler "^1.5.1" - nocache "^3.0.1" - pretty-format "^26.6.2" - serve-static "^1.13.1" - ws "^7.5.1" - -"@react-native-community/cli-tools@11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-11.4.1.tgz#f6c69967e077b10cd8a884a83e53eb199dd9ee9f" - integrity sha512-GuQIuY/kCPfLeXB1aiPZ5HvF+e/wdO42AYuNEmT7FpH/0nAhdTxA9qjL8m3vatDD2/YK7WNOSVNsl2UBZuOISg== - dependencies: - appdirsjs "^1.2.4" - chalk "^4.1.2" - find-up "^5.0.0" - mime "^2.4.1" - node-fetch "^2.6.0" - open "^6.2.0" - ora "^5.4.1" - semver "^7.5.2" - shell-quote "^1.7.3" - -"@react-native-community/cli-types@11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-types/-/cli-types-11.4.1.tgz#3842dc37ba3b09f929b485bcbd8218de19349ac2" - integrity sha512-B3q9A5BCneLDSoK/iSJ06MNyBn1qTxjdJeOgeS3MiCxgJpPcxyn/Yrc6+h0Cu9T9sgWj/dmectQPYWxtZeo5VA== - dependencies: - joi "^17.2.1" - -"@react-native-community/cli@^11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-11.4.1.tgz#9a6346486622860dad721da406df70e29a45491f" - integrity sha512-NdAageVMtNhtvRsrq4NgJf5Ey2nA1CqmLvn7PhSawg+aIzMKmZuzWxGVwr9CoPGyjvNiqJlCWrLGR7NzOyi/sA== - dependencies: - "@react-native-community/cli-clean" "11.4.1" - "@react-native-community/cli-config" "11.4.1" - "@react-native-community/cli-debugger-ui" "11.4.1" - "@react-native-community/cli-doctor" "11.4.1" - "@react-native-community/cli-hermes" "11.4.1" - "@react-native-community/cli-plugin-metro" "11.4.1" - "@react-native-community/cli-server-api" "11.4.1" - "@react-native-community/cli-tools" "11.4.1" - "@react-native-community/cli-types" "11.4.1" - chalk "^4.1.2" - commander "^9.4.1" - execa "^5.0.0" - find-up "^4.1.0" - fs-extra "^8.1.0" - graceful-fs "^4.1.3" - prompts "^2.4.0" - semver "^7.5.2" - -"@react-native/assets-registry@^0.72.0": - version "0.72.0" - resolved "https://registry.yarnpkg.com/@react-native/assets-registry/-/assets-registry-0.72.0.tgz#c82a76a1d86ec0c3907be76f7faf97a32bbed05d" - integrity sha512-Im93xRJuHHxb1wniGhBMsxLwcfzdYreSZVQGDoMJgkd6+Iky61LInGEHnQCTN0fKNYF1Dvcofb4uMmE1RQHXHQ== - -"@react-native/codegen@^0.72.8": - version "0.72.8" - resolved "https://registry.yarnpkg.com/@react-native/codegen/-/codegen-0.72.8.tgz#0593f628e1310f430450a9479fbb4be35e7b63d6" - integrity sha512-jQCcBlXV7B7ap5VlHhwIPieYz89yiRgwd2FPUBu+unz+kcJ6pAiB2U8RdLDmyIs8fiWd+Vq1xxaWs4TR329/ng== - dependencies: - "@babel/parser" "^7.20.0" - flow-parser "^0.206.0" - glob "^7.1.1" - invariant "^2.2.4" - jscodeshift "^0.14.0" - mkdirp "^0.5.1" - nullthrows "^1.1.1" - -"@react-native/eslint-config@^0.72.2": - version "0.72.2" - resolved "https://registry.yarnpkg.com/@react-native/eslint-config/-/eslint-config-0.72.2.tgz#31da4cec65ad2805d4db9fdda138452821d72133" - integrity sha512-rAYuQQXzi63W7+9Pu/+23od/b/lTSzHjMFibum3sKgdG2LIyvhoMEWQ5+Chu7TqebqYy1b9SDn/KEMHvpWFtNg== - dependencies: - "@babel/core" "^7.20.0" - "@babel/eslint-parser" "^7.20.0" - "@react-native/eslint-plugin" "^0.72.0" - "@typescript-eslint/eslint-plugin" "^5.30.5" - "@typescript-eslint/parser" "^5.30.5" - eslint-config-prettier "^8.5.0" - eslint-plugin-eslint-comments "^3.2.0" - eslint-plugin-ft-flow "^2.0.1" - eslint-plugin-jest "^26.5.3" - eslint-plugin-prettier "^4.2.1" - eslint-plugin-react "^7.30.1" - eslint-plugin-react-hooks "^4.6.0" - eslint-plugin-react-native "^4.0.0" - -"@react-native/eslint-plugin@^0.72.0": - version "0.72.0" - resolved "https://registry.yarnpkg.com/@react-native/eslint-plugin/-/eslint-plugin-0.72.0.tgz#7ec4c6a73dfde4bd6b4a4d3c462cfdc2637bf91d" - integrity sha512-xWQthnyKd+H22TBqeJUTFebsyWAAwzUb7EQCT8F/WMZsS1sv5UG+2cM/cU9/2HEbVZgxHYuLIi915WznjKPvlg== - -"@react-native/gradle-plugin@^0.72.11": - version "0.72.11" - resolved "https://registry.yarnpkg.com/@react-native/gradle-plugin/-/gradle-plugin-0.72.11.tgz#c063ef12778706611de7a1e42b74b14d9405fb9f" - integrity sha512-P9iRnxiR2w7EHcZ0mJ+fmbPzMby77ZzV6y9sJI3lVLJzF7TLSdbwcQyD3lwMsiL+q5lKUHoZJS4sYmih+P2HXw== - -"@react-native/js-polyfills@^0.72.1": - version "0.72.1" - resolved "https://registry.yarnpkg.com/@react-native/js-polyfills/-/js-polyfills-0.72.1.tgz#905343ef0c51256f128256330fccbdb35b922291" - integrity sha512-cRPZh2rBswFnGt5X5EUEPs0r+pAsXxYsifv/fgy9ZLQokuT52bPH+9xjDR+7TafRua5CttGW83wP4TntRcWNDA== - -"@react-native/metro-config@^0.72.12": - version "0.72.12" - resolved "https://registry.yarnpkg.com/@react-native/metro-config/-/metro-config-0.72.12.tgz#f55a0a68100824ac57989ee9ae9518a69b0c43c5" - integrity sha512-6NC5nr70oV8gH5vTz0yVYig6TGn97NfE58DdYottuOGPEODZf9Jpb7gdLs6Rqj5ryFDsKVPU3NsFmXKBJwEgXQ== - dependencies: - "@react-native/js-polyfills" "^0.72.1" - metro-config "^0.76.9" - metro-react-native-babel-transformer "^0.76.9" - metro-runtime "^0.76.9" - -"@react-native/normalize-colors@<0.73.0", "@react-native/normalize-colors@^0.72.0": - version "0.72.0" - resolved "https://registry.yarnpkg.com/@react-native/normalize-colors/-/normalize-colors-0.72.0.tgz#14294b7ed3c1d92176d2a00df48456e8d7d62212" - integrity sha512-285lfdqSXaqKuBbbtP9qL2tDrfxdOFtIMvkKadtleRQkdOxx+uzGvFr82KHmc/sSiMtfXGp7JnFYWVh4sFl7Yw== - -"@react-native/virtualized-lists@^0.72.8": - version "0.72.8" - resolved "https://registry.yarnpkg.com/@react-native/virtualized-lists/-/virtualized-lists-0.72.8.tgz#a2c6a91ea0f1d40eb5a122fb063daedb92ed1dc3" - integrity sha512-J3Q4Bkuo99k7mu+jPS9gSUSgq+lLRSI/+ahXNwV92XgJ/8UgOTxu2LPwhJnBk/sQKxq7E8WkZBnBiozukQMqrw== - dependencies: - invariant "^2.2.4" - nullthrows "^1.1.1" - -"@sideway/address@^4.1.5": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.5.tgz#4bc149a0076623ced99ca8208ba780d65a99b9d5" - integrity sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q== - dependencies: - "@hapi/hoek" "^9.0.0" - -"@sideway/formula@^3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.1.tgz#80fcbcbaf7ce031e0ef2dd29b1bfc7c3f583611f" - integrity sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg== - -"@sideway/pinpoint@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" - integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== - -"@sinclair/typebox@^0.27.8": - version "0.27.8" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" - integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== - -"@sinonjs/commons@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" - integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== - dependencies: - type-detect "4.0.8" - -"@sinonjs/fake-timers@^10.0.2": - version "10.3.0" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" - integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== - dependencies: - "@sinonjs/commons" "^3.0.0" - -"@tsconfig/react-native@^3.0.0": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@tsconfig/react-native/-/react-native-3.0.5.tgz#c4971b1eca2e8cdf7b0d25f40193a782039c1abd" - integrity sha512-0+pmYzHccvwWpFz2Tv5AJxp6UroLALmAy+SX34tKlwaCie1mNbtCv6uOJp7x8pKchgNA9/n6BGrx7uLQvw8p9A== - -"@types/babel__core@^7.1.14": - version "7.20.5" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" - integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== - dependencies: - "@babel/parser" "^7.20.7" - "@babel/types" "^7.20.7" - "@types/babel__generator" "*" - "@types/babel__template" "*" - "@types/babel__traverse" "*" - -"@types/babel__generator@*": - version "7.6.8" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" - integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== - dependencies: - "@babel/types" "^7.0.0" - -"@types/babel__template@*": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" - integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": - version "7.20.6" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" - integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== - dependencies: - "@babel/types" "^7.20.7" - -"@types/graceful-fs@^4.1.3": - version "4.1.9" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" - integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== - dependencies: - "@types/node" "*" - -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": - version "2.0.6" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" - integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== - -"@types/istanbul-lib-report@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" - integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== - dependencies: - "@types/istanbul-lib-coverage" "*" - -"@types/istanbul-reports@^3.0.0": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" - integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== - dependencies: - "@types/istanbul-lib-report" "*" - -"@types/jest@^29.2.1": - version "29.5.14" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.14.tgz#2b910912fa1d6856cadcd0c1f95af7df1d6049e5" - integrity sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ== - dependencies: - expect "^29.0.0" - pretty-format "^29.0.0" - -"@types/json-schema@^7.0.9": - version "7.0.15" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" - integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== - -"@types/node@*": - version "22.13.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.13.0.tgz#d376dd9a0ee2f9382d86c2d5d7beb4d198b4ea8c" - integrity sha512-ClIbNe36lawluuvq3+YYhnIN2CELi+6q8NpnM7PYp4hBn/TatfboPgVSm2rwKRfnV2M+Ty9GWDFI64KEe+kysA== - dependencies: - undici-types "~6.20.0" - -"@types/prop-types@*": - version "15.7.14" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.14.tgz#1433419d73b2a7ebfc6918dcefd2ec0d5cd698f2" - integrity sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ== - -"@types/react-test-renderer@^18.0.0": - version "18.3.1" - resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-18.3.1.tgz#225bfe8d4ad7ee3b04c2fa27642bb74274a5961d" - integrity sha512-vAhnk0tG2eGa37lkU9+s5SoroCsRI08xnsWFiAXOuPH2jqzMbcXvKExXViPi1P5fIklDeCvXqyrdmipFaSkZrA== - dependencies: - "@types/react" "^18" - -"@types/react@^18", "@types/react@^18.0.24": - version "18.3.18" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.18.tgz#9b382c4cd32e13e463f97df07c2ee3bbcd26904b" - integrity sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ== - dependencies: - "@types/prop-types" "*" - csstype "^3.0.2" - -"@types/semver@^7.3.12": - version "7.5.8" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" - integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== - -"@types/stack-utils@^2.0.0": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" - integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== - -"@types/yargs-parser@*": - version "21.0.3" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" - integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== - -"@types/yargs@^15.0.0": - version "15.0.19" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.19.tgz#328fb89e46109ecbdb70c295d96ff2f46dfd01b9" - integrity sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA== - dependencies: - "@types/yargs-parser" "*" - -"@types/yargs@^16.0.0": - version "16.0.9" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.9.tgz#ba506215e45f7707e6cbcaf386981155b7ab956e" - integrity sha512-tHhzvkFXZQeTECenFoRljLBYPZJ7jAVxqqtEI0qTLOmuultnFp4I9yKE17vTuhf7BkhCu7I4XuemPgikDVuYqA== - dependencies: - "@types/yargs-parser" "*" - -"@types/yargs@^17.0.8": - version "17.0.33" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.33.tgz#8c32303da83eec050a84b3c7ae7b9f922d13e32d" - integrity sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA== - dependencies: - "@types/yargs-parser" "*" - -"@typescript-eslint/eslint-plugin@^5.30.5": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz#aeef0328d172b9e37d9bab6dbc13b87ed88977db" - integrity sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag== - dependencies: - "@eslint-community/regexpp" "^4.4.0" - "@typescript-eslint/scope-manager" "5.62.0" - "@typescript-eslint/type-utils" "5.62.0" - "@typescript-eslint/utils" "5.62.0" - debug "^4.3.4" - graphemer "^1.4.0" - ignore "^5.2.0" - natural-compare-lite "^1.4.0" - semver "^7.3.7" - tsutils "^3.21.0" - -"@typescript-eslint/parser@^5.30.5": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.62.0.tgz#1b63d082d849a2fcae8a569248fbe2ee1b8a56c7" - integrity sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA== - dependencies: - "@typescript-eslint/scope-manager" "5.62.0" - "@typescript-eslint/types" "5.62.0" - "@typescript-eslint/typescript-estree" "5.62.0" - debug "^4.3.4" - -"@typescript-eslint/scope-manager@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c" - integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w== - dependencies: - "@typescript-eslint/types" "5.62.0" - "@typescript-eslint/visitor-keys" "5.62.0" - -"@typescript-eslint/type-utils@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz#286f0389c41681376cdad96b309cedd17d70346a" - integrity sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew== - dependencies: - "@typescript-eslint/typescript-estree" "5.62.0" - "@typescript-eslint/utils" "5.62.0" - debug "^4.3.4" - tsutils "^3.21.0" - -"@typescript-eslint/types@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" - integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== - -"@typescript-eslint/typescript-estree@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" - integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA== - dependencies: - "@typescript-eslint/types" "5.62.0" - "@typescript-eslint/visitor-keys" "5.62.0" - debug "^4.3.4" - globby "^11.1.0" - is-glob "^4.0.3" - semver "^7.3.7" - tsutils "^3.21.0" - -"@typescript-eslint/utils@5.62.0", "@typescript-eslint/utils@^5.10.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86" - integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ== - dependencies: - "@eslint-community/eslint-utils" "^4.2.0" - "@types/json-schema" "^7.0.9" - "@types/semver" "^7.3.12" - "@typescript-eslint/scope-manager" "5.62.0" - "@typescript-eslint/types" "5.62.0" - "@typescript-eslint/typescript-estree" "5.62.0" - eslint-scope "^5.1.1" - semver "^7.3.7" - -"@typescript-eslint/visitor-keys@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e" - integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw== - dependencies: - "@typescript-eslint/types" "5.62.0" - eslint-visitor-keys "^3.3.0" - -abort-controller@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" - integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== - dependencies: - event-target-shim "^5.0.0" - -accepts@^1.3.7, accepts@~1.3.7: - version "1.3.8" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" - integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== - dependencies: - mime-types "~2.1.34" - negotiator "0.6.3" - -acorn@^8.8.2: - version "8.14.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" - integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== - -ajv@^8.6.3: - version "8.17.1" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" - integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== - dependencies: - fast-deep-equal "^3.1.3" - fast-uri "^3.0.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - -anser@^1.4.9: - version "1.4.10" - resolved "https://registry.yarnpkg.com/anser/-/anser-1.4.10.tgz#befa3eddf282684bd03b63dcda3927aef8c2e35b" - integrity sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww== - -ansi-escapes@^4.2.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== - dependencies: - type-fest "^0.21.3" - -ansi-fragments@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/ansi-fragments/-/ansi-fragments-0.2.1.tgz#24409c56c4cc37817c3d7caa99d8969e2de5a05e" - integrity sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w== - dependencies: - colorette "^1.0.7" - slice-ansi "^2.0.0" - strip-ansi "^5.0.0" - -ansi-regex@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" - integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== - -ansi-regex@^5.0.0, ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^3.2.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-styles@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" - integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== - -anymatch@^3.0.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" - integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -appdirsjs@^1.2.4: - version "1.2.7" - resolved "https://registry.yarnpkg.com/appdirsjs/-/appdirsjs-1.2.7.tgz#50b4b7948a26ba6090d4aede2ae2dc2b051be3b3" - integrity sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw== - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -array-buffer-byte-length@^1.0.1, array-buffer-byte-length@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz#384d12a37295aec3769ab022ad323a18a51ccf8b" - integrity sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw== - dependencies: - call-bound "^1.0.3" - is-array-buffer "^3.0.5" - -array-includes@^3.1.6, array-includes@^3.1.8: - version "3.1.8" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" - integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.2" - es-object-atoms "^1.0.0" - get-intrinsic "^1.2.4" - is-string "^1.0.7" - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -array.prototype.findlast@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz#3e4fbcb30a15a7f5bf64cf2faae22d139c2e4904" - integrity sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.2" - es-errors "^1.3.0" - es-object-atoms "^1.0.0" - es-shim-unscopables "^1.0.2" - -array.prototype.flat@^1.3.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz#534aaf9e6e8dd79fb6b9a9917f839ef1ec63afe5" - integrity sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg== - dependencies: - call-bind "^1.0.8" - define-properties "^1.2.1" - es-abstract "^1.23.5" - es-shim-unscopables "^1.0.2" - -array.prototype.flatmap@^1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz#712cc792ae70370ae40586264629e33aab5dd38b" - integrity sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg== - dependencies: - call-bind "^1.0.8" - define-properties "^1.2.1" - es-abstract "^1.23.5" - es-shim-unscopables "^1.0.2" - -array.prototype.tosorted@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz#fe954678ff53034e717ea3352a03f0b0b86f7ffc" - integrity sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.3" - es-errors "^1.3.0" - es-shim-unscopables "^1.0.2" - -arraybuffer.prototype.slice@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz#9d760d84dbdd06d0cbf92c8849615a1a7ab3183c" - integrity sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ== - dependencies: - array-buffer-byte-length "^1.0.1" - call-bind "^1.0.8" - define-properties "^1.2.1" - es-abstract "^1.23.5" - es-errors "^1.3.0" - get-intrinsic "^1.2.6" - is-array-buffer "^3.0.4" - -asap@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== - -ast-types@0.15.2: - version "0.15.2" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.15.2.tgz#39ae4809393c4b16df751ee563411423e85fb49d" - integrity sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg== - dependencies: - tslib "^2.0.1" - -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - -async-function@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/async-function/-/async-function-1.0.0.tgz#509c9fca60eaf85034c6829838188e4e4c8ffb2b" - integrity sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA== - -async-limiter@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" - integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== - -async@^3.2.2: - version "3.2.6" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" - integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== - -available-typed-arrays@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" - integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== - dependencies: - possible-typed-array-names "^1.0.0" - -babel-core@^7.0.0-bridge.0: - version "7.0.0-bridge.0" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece" - integrity sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg== - -babel-jest@^29.2.1, babel-jest@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" - integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== - dependencies: - "@jest/transform" "^29.7.0" - "@types/babel__core" "^7.1.14" - babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^29.6.3" - chalk "^4.0.0" - graceful-fs "^4.2.9" - slash "^3.0.0" - -babel-plugin-istanbul@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" - integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@istanbuljs/load-nyc-config" "^1.0.0" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-instrument "^5.0.4" - test-exclude "^6.0.0" - -babel-plugin-jest-hoist@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" - integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== - dependencies: - "@babel/template" "^7.3.3" - "@babel/types" "^7.3.3" - "@types/babel__core" "^7.1.14" - "@types/babel__traverse" "^7.0.6" - -babel-plugin-module-resolver@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/babel-plugin-module-resolver/-/babel-plugin-module-resolver-4.1.0.tgz#22a4f32f7441727ec1fbf4967b863e1e3e9f33e2" - integrity sha512-MlX10UDheRr3lb3P0WcaIdtCSRlxdQsB1sBqL7W0raF070bGl1HQQq5K3T2vf2XAYie+ww+5AKC/WrkjRO2knA== - dependencies: - find-babel-config "^1.2.0" - glob "^7.1.6" - pkg-up "^3.1.0" - reselect "^4.0.0" - resolve "^1.13.1" - -babel-plugin-polyfill-corejs2@^0.4.10: - version "0.4.12" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.12.tgz#ca55bbec8ab0edeeef3d7b8ffd75322e210879a9" - integrity sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og== - dependencies: - "@babel/compat-data" "^7.22.6" - "@babel/helper-define-polyfill-provider" "^0.6.3" - semver "^6.3.1" - -babel-plugin-polyfill-corejs3@^0.10.6: - version "0.10.6" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz#2deda57caef50f59c525aeb4964d3b2f867710c7" - integrity sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.6.2" - core-js-compat "^3.38.0" - -babel-plugin-polyfill-regenerator@^0.6.1: - version "0.6.3" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.3.tgz#abeb1f3f1c762eace37587f42548b08b57789bc8" - integrity sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.6.3" - -babel-plugin-syntax-trailing-function-commas@^7.0.0-beta.0: - version "7.0.0-beta.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz#aa213c1435e2bffeb6fca842287ef534ad05d5cf" - integrity sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ== - -babel-plugin-transform-flow-enums@^0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-enums/-/babel-plugin-transform-flow-enums-0.0.2.tgz#d1d0cc9bdc799c850ca110d0ddc9f21b9ec3ef25" - integrity sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ== - dependencies: - "@babel/plugin-syntax-flow" "^7.12.1" - -babel-preset-current-node-syntax@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz#9a929eafece419612ef4ae4f60b1862ebad8ef30" - integrity sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw== - dependencies: - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-bigint" "^7.8.3" - "@babel/plugin-syntax-class-properties" "^7.12.13" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - "@babel/plugin-syntax-import-attributes" "^7.24.7" - "@babel/plugin-syntax-import-meta" "^7.10.4" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - "@babel/plugin-syntax-top-level-await" "^7.14.5" - -babel-preset-fbjs@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/babel-preset-fbjs/-/babel-preset-fbjs-3.4.0.tgz#38a14e5a7a3b285a3f3a86552d650dca5cf6111c" - integrity sha512-9ywCsCvo1ojrw0b+XYk7aFvTH6D9064t0RIL1rtMf3nsa02Xw41MS7sZw216Im35xj/UY0PDBQsa1brUDDF1Ow== - dependencies: - "@babel/plugin-proposal-class-properties" "^7.0.0" - "@babel/plugin-proposal-object-rest-spread" "^7.0.0" - "@babel/plugin-syntax-class-properties" "^7.0.0" - "@babel/plugin-syntax-flow" "^7.0.0" - "@babel/plugin-syntax-jsx" "^7.0.0" - "@babel/plugin-syntax-object-rest-spread" "^7.0.0" - "@babel/plugin-transform-arrow-functions" "^7.0.0" - "@babel/plugin-transform-block-scoped-functions" "^7.0.0" - "@babel/plugin-transform-block-scoping" "^7.0.0" - "@babel/plugin-transform-classes" "^7.0.0" - "@babel/plugin-transform-computed-properties" "^7.0.0" - "@babel/plugin-transform-destructuring" "^7.0.0" - "@babel/plugin-transform-flow-strip-types" "^7.0.0" - "@babel/plugin-transform-for-of" "^7.0.0" - "@babel/plugin-transform-function-name" "^7.0.0" - "@babel/plugin-transform-literals" "^7.0.0" - "@babel/plugin-transform-member-expression-literals" "^7.0.0" - "@babel/plugin-transform-modules-commonjs" "^7.0.0" - "@babel/plugin-transform-object-super" "^7.0.0" - "@babel/plugin-transform-parameters" "^7.0.0" - "@babel/plugin-transform-property-literals" "^7.0.0" - "@babel/plugin-transform-react-display-name" "^7.0.0" - "@babel/plugin-transform-react-jsx" "^7.0.0" - "@babel/plugin-transform-shorthand-properties" "^7.0.0" - "@babel/plugin-transform-spread" "^7.0.0" - "@babel/plugin-transform-template-literals" "^7.0.0" - babel-plugin-syntax-trailing-function-commas "^7.0.0-beta.0" - -babel-preset-jest@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" - integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== - dependencies: - babel-plugin-jest-hoist "^29.6.3" - babel-preset-current-node-syntax "^1.0.0" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -base-64@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/base-64/-/base-64-0.1.0.tgz#780a99c84e7d600260361511c4877613bf24f6bb" - integrity sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA== - -base64-js@^1.1.2, base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -bl@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" - integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== - dependencies: - buffer "^5.5.0" - inherits "^2.0.4" - readable-stream "^3.4.0" - -bluebird@^3.5.4: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== - dependencies: - balanced-match "^1.0.0" - -braces@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" - integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== - dependencies: - fill-range "^7.1.1" - -browser-process-hrtime@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" - integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== - -browserslist@^4.24.0, browserslist@^4.24.3: - version "4.24.4" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.4.tgz#c6b2865a3f08bcb860a0e827389003b9fe686e4b" - integrity sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A== - dependencies: - caniuse-lite "^1.0.30001688" - electron-to-chromium "^1.5.73" - node-releases "^2.0.19" - update-browserslist-db "^1.1.1" - -bser@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" - integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== - dependencies: - node-int64 "^0.4.0" - -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - -buffer@^5.5.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - -bunyan-debug-stream@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/bunyan-debug-stream/-/bunyan-debug-stream-3.1.1.tgz#e3bcb36bbf95f11b5945891cf2618625fe64985c" - integrity sha512-LfMcz4yKM6s9BP5dfT63Prb5B2hAjReLAfQzLbNQF7qBHtn3P1v+/yn0SZ6UAr4PC3VZRX/QzK7HYkkY0ytokQ== - dependencies: - chalk "^4.1.2" - -bunyan@^1.8.12: - version "1.8.15" - resolved "https://registry.yarnpkg.com/bunyan/-/bunyan-1.8.15.tgz#8ce34ca908a17d0776576ca1b2f6cbd916e93b46" - integrity sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig== - optionalDependencies: - dtrace-provider "~0.8" - moment "^2.19.3" - mv "~2" - safe-json-stringify "~1" - -bytes@3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" - integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== - -caf@^15.0.1: - version "15.0.1" - resolved "https://registry.yarnpkg.com/caf/-/caf-15.0.1.tgz#28f1f17bd93dc4b5d95207ad07066eddf4768160" - integrity sha512-Xp/IK6vMwujxWZXra7djdYzPdPnEQKa7Mudu2wZgDQ3TJry1I0TgtjEgwZHpoBcMp68j4fb0/FZ1SJyMEgJrXQ== - -call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz#32e5892e6361b29b0b545ba6f7763378daca2840" - integrity sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g== - dependencies: - es-errors "^1.3.0" - function-bind "^1.1.2" - -call-bind@^1.0.7, call-bind@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c" - integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== - dependencies: - call-bind-apply-helpers "^1.0.0" - es-define-property "^1.0.0" - get-intrinsic "^1.2.4" - set-function-length "^1.2.2" - -call-bound@^1.0.2, call-bound@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.3.tgz#41cfd032b593e39176a71533ab4f384aa04fd681" - integrity sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA== - dependencies: - call-bind-apply-helpers "^1.0.1" - get-intrinsic "^1.2.6" - -caller-callsite@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" - integrity sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ== - dependencies: - callsites "^2.0.0" - -caller-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" - integrity sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A== - dependencies: - caller-callsite "^2.0.0" - -callsites@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" - integrity sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ== - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -camelcase@^5.0.0, camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -camelcase@^6.0.0, camelcase@^6.2.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" - integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== - -caniuse-lite@^1.0.30001688: - version "1.0.30001696" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001696.tgz#00c30a2fc11e3c98c25e5125418752af3ae2f49f" - integrity sha512-pDCPkvzfa39ehJtJ+OwGT/2yvT2SbjfHhiIW2LWOAcMQ7BzwxT/XuyUp4OTOd0XFWA6BKw0JalnBHgSi5DGJBQ== - -chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -char-regex@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" - integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== - -child-process-promise@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/child-process-promise/-/child-process-promise-2.2.1.tgz#4730a11ef610fad450b8f223c79d31d7bdad8074" - integrity sha512-Fi4aNdqBsr0mv+jgWxcZ/7rAIC2mgihrptyVI4foh/rrjY/3BNjfP9+oaiFx/fzim+1ZyCNBae0DlyfQhSugog== - dependencies: - cross-spawn "^4.0.2" - node-version "^1.0.0" - promise-polyfill "^6.0.1" - -ci-info@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" - integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== - -ci-info@^3.2.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" - integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== - -cjs-module-lexer@^1.0.0: - version "1.4.3" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz#0f79731eb8cfe1ec72acd4066efac9d61991b00d" - integrity sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q== - -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - -cli-spinners@^2.5.0: - version "2.9.2" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41" - integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== - -cliui@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" - integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^6.2.0" - -cliui@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" - integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.1" - wrap-ansi "^7.0.0" - -clone-deep@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" - integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== - dependencies: - is-plain-object "^2.0.4" - kind-of "^6.0.2" - shallow-clone "^3.0.0" - -clone@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== - -collect-v8-coverage@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" - integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -colorette@^1.0.7: - version "1.4.0" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" - integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== - -command-exists@^1.2.8: - version "1.2.9" - resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69" - integrity sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== - -commander@^2.20.0: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -commander@^9.4.1: - version "9.5.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" - integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== - -commander@~2.13.0: - version "2.13.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" - integrity sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA== - -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== - -compressible@~2.0.18: - version "2.0.18" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" - integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== - dependencies: - mime-db ">= 1.43.0 < 2" - -compression@^1.7.1: - version "1.7.5" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.5.tgz#fdd256c0a642e39e314c478f6c2cd654edd74c93" - integrity sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q== - dependencies: - bytes "3.1.2" - compressible "~2.0.18" - debug "2.6.9" - negotiator "~0.6.4" - on-headers "~1.0.2" - safe-buffer "5.2.1" - vary "~1.1.2" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -connect@^3.6.5: - version "3.7.0" - resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8" - integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ== - dependencies: - debug "2.6.9" - finalhandler "1.1.2" - parseurl "~1.3.3" - utils-merge "1.0.1" - -convert-source-map@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" - integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== - -core-js-compat@^3.38.0, core-js-compat@^3.38.1: - version "3.40.0" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.40.0.tgz#7485912a5a4a4315c2fdb2cbdc623e6881c88b38" - integrity sha512-0XEDpr5y5mijvw8Lbc6E5AkjrHfp7eEoPlu36SWeAbcL8fn1G1ANe8DBlo2XoNN89oVpxWwOjYIPVzR4ZvsKCQ== - dependencies: - browserslist "^4.24.3" - -core-util-is@~1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" - integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== - -cosmiconfig@^5.0.5, cosmiconfig@^5.1.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" - integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== - dependencies: - import-fresh "^2.0.0" - is-directory "^0.3.1" - js-yaml "^3.13.1" - parse-json "^4.0.0" - -create-jest@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" - integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== - dependencies: - "@jest/types" "^29.6.3" - chalk "^4.0.0" - exit "^0.1.2" - graceful-fs "^4.2.9" - jest-config "^29.7.0" - jest-util "^29.7.0" - prompts "^2.0.1" - -cross-spawn@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-4.0.2.tgz#7b9247621c23adfdd3856004a823cbe397424d41" - integrity sha512-yAXz/pA1tD8Gtg2S98Ekf/sewp3Lcp3YoFKJ4Hkp5h5yLWnKVTDU0kwjKJ8NDCYcfTLfyGkzTikst+jWypT1iA== - dependencies: - lru-cache "^4.0.1" - which "^1.2.9" - -cross-spawn@^7.0.3: - version "7.0.6" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" - integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -csstype@^3.0.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" - integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== - -data-view-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz#211a03ba95ecaf7798a8c7198d79536211f88570" - integrity sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ== - dependencies: - call-bound "^1.0.3" - es-errors "^1.3.0" - is-data-view "^1.0.2" - -data-view-byte-length@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz#9e80f7ca52453ce3e93d25a35318767ea7704735" - integrity sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ== - dependencies: - call-bound "^1.0.3" - es-errors "^1.3.0" - is-data-view "^1.0.2" - -data-view-byte-offset@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz#068307f9b71ab76dbbe10291389e020856606191" - integrity sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ== - dependencies: - call-bound "^1.0.2" - es-errors "^1.3.0" - is-data-view "^1.0.1" - -dayjs@^1.8.15: - version "1.11.13" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" - integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== - -debug@2.6.9, debug@^2.2.0: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4: - version "4.4.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" - integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== - dependencies: - ms "^2.1.3" - -decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== - -decamelize@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" - integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== - -dedent@^1.0.0: - version "1.5.3" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a" - integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== - -deepmerge@^4.2.2, deepmerge@^4.3.0: - version "4.3.1" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" - integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== - -defaults@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.4.tgz#b0b02062c1e2aa62ff5d9528f0f98baa90978d7a" - integrity sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A== - dependencies: - clone "^1.0.2" - -define-data-property@^1.0.1, define-data-property@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" - integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== - dependencies: - es-define-property "^1.0.0" - es-errors "^1.3.0" - gopd "^1.0.1" - -define-properties@^1.1.3, define-properties@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" - integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== - dependencies: - define-data-property "^1.0.1" - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - -denodeify@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/denodeify/-/denodeify-1.2.1.tgz#3a36287f5034e699e7577901052c2e6c94251631" - integrity sha512-KNTihKNmQENUZeKu5fzfpzRqR5S2VMp4gl9RFHiWzj9DfvYQPMJ6XHKNaQxaGCXwPk6y9yme3aUoaiAe+KX+vg== - -depd@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" - integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== - -deprecated-react-native-prop-types@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-4.2.3.tgz#0ef845c1a80ef1636bd09060e4cdf70f9727e5ad" - integrity sha512-2rLTiMKidIFFYpIVM69UnQKngLqQfL6I11Ch8wGSBftS18FUXda+o2we2950X+1dmbgps28niI3qwyH4eX3Z1g== - dependencies: - "@react-native/normalize-colors" "<0.73.0" - invariant "^2.2.4" - prop-types "^15.8.1" - -destroy@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" - integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== - -detect-newline@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" - integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== - -detox@20.10.0: - version "20.10.0" - resolved "https://registry.yarnpkg.com/detox/-/detox-20.10.0.tgz#2c8df147c6f81d57b22f79f6bc252b8d71438a64" - integrity sha512-c6dCD5xTmiuOklbx4ptnXuznCnK4IMd9ZtB8jXxNJBqZpUXzqhmCniwKPZNwkdtye/xXbEFz4t5JWQKsVJ3z5Q== - dependencies: - ajv "^8.6.3" - bunyan "^1.8.12" - bunyan-debug-stream "^3.1.0" - caf "^15.0.1" - chalk "^4.0.0" - child-process-promise "^2.2.0" - execa "^5.1.1" - find-up "^5.0.0" - fs-extra "^11.0.0" - funpermaproxy "^1.1.0" - glob "^8.0.3" - ini "^1.3.4" - json-cycle "^1.3.0" - lodash "^4.17.11" - multi-sort-stream "^1.0.3" - multipipe "^4.0.0" - node-ipc "9.2.1" - proper-lockfile "^3.0.2" - resolve-from "^5.0.0" - sanitize-filename "^1.6.1" - semver "^7.0.0" - serialize-error "^8.0.1" - shell-quote "^1.7.2" - signal-exit "^3.0.3" - stream-json "^1.7.4" - strip-ansi "^6.0.1" - telnet-client "1.2.8" - tempfile "^2.0.0" - trace-event-lib "^1.3.1" - which "^1.3.1" - ws "^7.0.0" - yargs "^17.0.0" - yargs-parser "^21.0.0" - yargs-unparser "^2.0.0" - -diff-sequences@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" - integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - -dtrace-provider@~0.8: - version "0.8.8" - resolved "https://registry.yarnpkg.com/dtrace-provider/-/dtrace-provider-0.8.8.tgz#2996d5490c37e1347be263b423ed7b297fb0d97e" - integrity sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg== - dependencies: - nan "^2.14.0" - -dunder-proto@^1.0.0, dunder-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" - integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== - dependencies: - call-bind-apply-helpers "^1.0.1" - es-errors "^1.3.0" - gopd "^1.2.0" - -duplexer2@^0.1.2: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" - integrity sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA== - dependencies: - readable-stream "^2.0.2" - -easy-stack@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/easy-stack/-/easy-stack-1.0.1.tgz#8afe4264626988cabb11f3c704ccd0c835411066" - integrity sha512-wK2sCs4feiiJeFXn3zvY0p41mdU5VUgbgs1rNsc/y5ngFUijdWd+iIN8eoyuZHKB8xN6BL4PdWmzqFmxNg6V2w== - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== - -electron-to-chromium@^1.5.73: - version "1.5.90" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.90.tgz#4717e5a5413f95bbb12d0af14c35057e9c65e0b6" - integrity sha512-C3PN4aydfW91Natdyd449Kw+BzhLmof6tzy5W1pFC5SpQxVXT+oyiyOG9AgYYSN9OdA/ik3YkCrpwqI8ug5Tug== - -emittery@^0.13.1: - version "0.13.1" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" - integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== - -encodeurl@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" - integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== - -envinfo@^7.7.2: - version "7.14.0" - resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.14.0.tgz#26dac5db54418f2a4c1159153a0b2ae980838aae" - integrity sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg== - -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -error-stack-parser@^2.0.6: - version "2.1.4" - resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.1.4.tgz#229cb01cdbfa84440bfa91876285b94680188286" - integrity sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ== - dependencies: - stackframe "^1.3.4" - -errorhandler@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/errorhandler/-/errorhandler-1.5.1.tgz#b9ba5d17cf90744cd1e851357a6e75bf806a9a91" - integrity sha512-rcOwbfvP1WTViVoUjcfZicVzjhjTuhSMntHh6mW3IrEiyE6mJyXvsToJUJGlGlw/2xU9P5whlWNGlIDVeCiT4A== - dependencies: - accepts "~1.3.7" - escape-html "~1.0.3" - -es-abstract@^1.17.5, es-abstract@^1.23.2, es-abstract@^1.23.3, es-abstract@^1.23.5, es-abstract@^1.23.6, es-abstract@^1.23.9: - version "1.23.9" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.9.tgz#5b45994b7de78dada5c1bebf1379646b32b9d606" - integrity sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA== - dependencies: - array-buffer-byte-length "^1.0.2" - arraybuffer.prototype.slice "^1.0.4" - available-typed-arrays "^1.0.7" - call-bind "^1.0.8" - call-bound "^1.0.3" - data-view-buffer "^1.0.2" - data-view-byte-length "^1.0.2" - data-view-byte-offset "^1.0.1" - es-define-property "^1.0.1" - es-errors "^1.3.0" - es-object-atoms "^1.0.0" - es-set-tostringtag "^2.1.0" - es-to-primitive "^1.3.0" - function.prototype.name "^1.1.8" - get-intrinsic "^1.2.7" - get-proto "^1.0.0" - get-symbol-description "^1.1.0" - globalthis "^1.0.4" - gopd "^1.2.0" - has-property-descriptors "^1.0.2" - has-proto "^1.2.0" - has-symbols "^1.1.0" - hasown "^2.0.2" - internal-slot "^1.1.0" - is-array-buffer "^3.0.5" - is-callable "^1.2.7" - is-data-view "^1.0.2" - is-regex "^1.2.1" - is-shared-array-buffer "^1.0.4" - is-string "^1.1.1" - is-typed-array "^1.1.15" - is-weakref "^1.1.0" - math-intrinsics "^1.1.0" - object-inspect "^1.13.3" - object-keys "^1.1.1" - object.assign "^4.1.7" - own-keys "^1.0.1" - regexp.prototype.flags "^1.5.3" - safe-array-concat "^1.1.3" - safe-push-apply "^1.0.0" - safe-regex-test "^1.1.0" - set-proto "^1.0.0" - string.prototype.trim "^1.2.10" - string.prototype.trimend "^1.0.9" - string.prototype.trimstart "^1.0.8" - typed-array-buffer "^1.0.3" - typed-array-byte-length "^1.0.3" - typed-array-byte-offset "^1.0.4" - typed-array-length "^1.0.7" - unbox-primitive "^1.1.0" - which-typed-array "^1.1.18" - -es-define-property@^1.0.0, es-define-property@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" - integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== - -es-errors@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" - integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== - -es-iterator-helpers@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz#d1dd0f58129054c0ad922e6a9a1e65eef435fe75" - integrity sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w== - dependencies: - call-bind "^1.0.8" - call-bound "^1.0.3" - define-properties "^1.2.1" - es-abstract "^1.23.6" - es-errors "^1.3.0" - es-set-tostringtag "^2.0.3" - function-bind "^1.1.2" - get-intrinsic "^1.2.6" - globalthis "^1.0.4" - gopd "^1.2.0" - has-property-descriptors "^1.0.2" - has-proto "^1.2.0" - has-symbols "^1.1.0" - internal-slot "^1.1.0" - iterator.prototype "^1.1.4" - safe-array-concat "^1.1.3" - -es-object-atoms@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" - integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== - dependencies: - es-errors "^1.3.0" - -es-set-tostringtag@^2.0.3, es-set-tostringtag@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" - integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== - dependencies: - es-errors "^1.3.0" - get-intrinsic "^1.2.6" - has-tostringtag "^1.0.2" - hasown "^2.0.2" - -es-shim-unscopables@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" - integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== - dependencies: - hasown "^2.0.0" - -es-to-primitive@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.3.0.tgz#96c89c82cc49fd8794a24835ba3e1ff87f214e18" - integrity sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g== - dependencies: - is-callable "^1.2.7" - is-date-object "^1.0.5" - is-symbol "^1.0.4" - -escalade@^3.1.1, escalade@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" - integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== - -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -escape-string-regexp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" - integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== - -eslint-config-prettier@^8.5.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz#3a06a662130807e2502fc3ff8b4143d8a0658e11" - integrity sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg== - -eslint-plugin-eslint-comments@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz#9e1cd7b4413526abb313933071d7aba05ca12ffa" - integrity sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ== - dependencies: - escape-string-regexp "^1.0.5" - ignore "^5.0.5" - -eslint-plugin-ft-flow@^2.0.1: - version "2.0.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-ft-flow/-/eslint-plugin-ft-flow-2.0.3.tgz#3b3c113c41902bcbacf0e22b536debcfc3c819e8" - integrity sha512-Vbsd/b+LYA99jUbsL6viEUWShFaYQt2YQs3QN3f+aeszOhh2sgdcU0mjzDyD4yyBvMc8qy2uwvBBWfMzEX06tg== - dependencies: - lodash "^4.17.21" - string-natural-compare "^3.0.1" - -eslint-plugin-jest@^26.5.3: - version "26.9.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-26.9.0.tgz#7931c31000b1c19e57dbfb71bbf71b817d1bf949" - integrity sha512-TWJxWGp1J628gxh2KhaH1H1paEdgE2J61BBF1I59c6xWeL5+D1BzMxGDN/nXAfX+aSkR5u80K+XhskK6Gwq9ng== - dependencies: - "@typescript-eslint/utils" "^5.10.0" - -eslint-plugin-prettier@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b" - integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ== - dependencies: - prettier-linter-helpers "^1.0.0" - -eslint-plugin-react-hooks@^4.6.0: - version "4.6.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz#c829eb06c0e6f484b3fbb85a97e57784f328c596" - integrity sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ== - -eslint-plugin-react-native-globals@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz#ee1348bc2ceb912303ce6bdbd22e2f045ea86ea2" - integrity sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g== - -eslint-plugin-react-native@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-native/-/eslint-plugin-react-native-4.1.0.tgz#5343acd3b2246bc1b857ac38be708f070d18809f" - integrity sha512-QLo7rzTBOl43FvVqDdq5Ql9IoElIuTdjrz9SKAXCvULvBoRZ44JGSkx9z4999ZusCsb4rK3gjS8gOGyeYqZv2Q== - dependencies: - eslint-plugin-react-native-globals "^0.1.1" - -eslint-plugin-react@^7.30.1: - version "7.37.4" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz#1b6c80b6175b6ae4b26055ae4d55d04c414c7181" - integrity sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ== - dependencies: - array-includes "^3.1.8" - array.prototype.findlast "^1.2.5" - array.prototype.flatmap "^1.3.3" - array.prototype.tosorted "^1.1.4" - doctrine "^2.1.0" - es-iterator-helpers "^1.2.1" - estraverse "^5.3.0" - hasown "^2.0.2" - jsx-ast-utils "^2.4.1 || ^3.0.0" - minimatch "^3.1.2" - object.entries "^1.1.8" - object.fromentries "^2.0.8" - object.values "^1.2.1" - prop-types "^15.8.1" - resolve "^2.0.0-next.5" - semver "^6.3.1" - string.prototype.matchall "^4.0.12" - string.prototype.repeat "^1.0.0" - -eslint-scope@5.1.1, eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-visitor-keys@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.3: - version "3.4.3" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" - integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== - -esprima@^4.0.0, esprima@~4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.2.0, estraverse@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== - -event-pubsub@4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/event-pubsub/-/event-pubsub-4.3.0.tgz#f68d816bc29f1ec02c539dc58c8dd40ce72cb36e" - integrity sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ== - -event-target-shim@^5.0.0, event-target-shim@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" - integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== - -execa@^5.0.0, execa@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - -exit@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== - -expect@^29.0.0, expect@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" - integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== - dependencies: - "@jest/expect-utils" "^29.7.0" - jest-get-type "^29.6.3" - jest-matcher-utils "^29.7.0" - jest-message-util "^29.7.0" - jest-util "^29.7.0" - -fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-diff@^1.1.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" - integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== - -fast-glob@^3.2.9: - version "3.3.3" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" - integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.8" - -fast-json-stable-stringify@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-uri@^3.0.1: - version "3.0.6" - resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.6.tgz#88f130b77cfaea2378d56bf970dea21257a68748" - integrity sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw== - -fast-xml-parser@^4.0.12: - version "4.5.1" - resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.5.1.tgz#a7e665ff79b7919100a5202f23984b6150f9b31e" - integrity sha512-y655CeyUQ+jj7KBbYMc4FG01V8ZQqjN+gDYGJ50RtfsUB8iG9AmwmwoAgeKLJdmueKKMrH1RJ7yXHTSoczdv5w== - dependencies: - strnum "^1.0.5" - -fastq@^1.6.0: - version "1.19.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.0.tgz#a82c6b7c2bb4e44766d865f07997785fecfdcb89" - integrity sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA== - dependencies: - reusify "^1.0.4" - -fb-watchman@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" - integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== - dependencies: - bser "2.1.1" - -fill-range@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" - integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== - dependencies: - to-regex-range "^5.0.1" - -finalhandler@1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" - integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.3" - statuses "~1.5.0" - unpipe "~1.0.0" - -find-babel-config@^1.2.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/find-babel-config/-/find-babel-config-1.2.2.tgz#41199b5cb9154dcb2fdc351cbe70eaf9198d5111" - integrity sha512-oK59njMyw2y3yxto1BCfVK7MQp/OYf4FleHu0RgosH3riFJ1aOuo/7naLDLAObfrgn3ueFhw5sAT/cp0QuJI3Q== - dependencies: - json5 "^1.0.2" - path-exists "^3.0.0" - -find-cache-dir@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" - integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== - dependencies: - commondir "^1.0.1" - make-dir "^2.0.0" - pkg-dir "^3.0.0" - -find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - -find-up@^4.0.0, find-up@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -find-up@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - -flat@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" - integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== - -flow-enums-runtime@^0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/flow-enums-runtime/-/flow-enums-runtime-0.0.5.tgz#95884bfcc82edaf27eef7e1dd09732331cfbafbc" - integrity sha512-PSZF9ZuaZD03sT9YaIs0FrGJ7lSUw7rHZIex+73UYVXg46eL/wxN5PaVcPJFudE2cJu5f0fezitV5aBkLHPUOQ== - -flow-parser@0.*: - version "0.259.1" - resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.259.1.tgz#2ab828be197bb87f47af299e5b734eab139bd269" - integrity sha512-xiXLmMH2Z7OmdE9Q+MjljUMr/rbemFqZIRxaeZieVScG4HzQrKKhNcCYZbWTGpoN7ZPi7z8ClQbeVPq6t5AszQ== - -flow-parser@^0.206.0: - version "0.206.0" - resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.206.0.tgz#f4f794f8026535278393308e01ea72f31000bfef" - integrity sha512-HVzoK3r6Vsg+lKvlIZzaWNBVai+FXTX1wdYhz/wVlH13tb/gOdLXmlTqy6odmTBhT5UoWUbq0k8263Qhr9d88w== - -for-each@^0.3.3: - version "0.3.4" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.4.tgz#814517ffc303d1399b2564d8165318e735d0341c" - integrity sha512-kKaIINnFpzW6ffJNDjjyjrk21BkDx38c0xa/klsT8VzLCaMEefv4ZTacrcVR4DmgTeBra++jMDAfS/tS799YDw== - dependencies: - is-callable "^1.2.7" - -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== - -fs-extra@^11.0.0: - version "11.3.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.3.0.tgz#0daced136bbaf65a555a326719af931adc7a314d" - integrity sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs-extra@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - -fsevents@^2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - -function-bind@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" - integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== - -function.prototype.name@^1.1.6, function.prototype.name@^1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.8.tgz#e68e1df7b259a5c949eeef95cdbde53edffabb78" - integrity sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q== - dependencies: - call-bind "^1.0.8" - call-bound "^1.0.3" - define-properties "^1.2.1" - functions-have-names "^1.2.3" - hasown "^2.0.2" - is-callable "^1.2.7" - -functions-have-names@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" - integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== - -funpermaproxy@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/funpermaproxy/-/funpermaproxy-1.1.0.tgz#39cb0b8bea908051e4608d8a414f1d87b55bf557" - integrity sha512-2Sp1hWuO8m5fqeFDusyhKqYPT+7rGLw34N3qonDcdRP8+n7M7Gl/yKp/q7oCxnnJ6pWCectOmLFJpsMU/++KrQ== - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -get-caller-file@^2.0.1, get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.7.tgz#dcfcb33d3272e15f445d15124bc0a216189b9044" - integrity sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA== - dependencies: - call-bind-apply-helpers "^1.0.1" - es-define-property "^1.0.1" - es-errors "^1.3.0" - es-object-atoms "^1.0.0" - function-bind "^1.1.2" - get-proto "^1.0.0" - gopd "^1.2.0" - has-symbols "^1.1.0" - hasown "^2.0.2" - math-intrinsics "^1.1.0" - -get-package-type@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" - integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== - -get-proto@^1.0.0, get-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" - integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== - dependencies: - dunder-proto "^1.0.1" - es-object-atoms "^1.0.0" - -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - -get-symbol-description@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.1.0.tgz#7bdd54e0befe8ffc9f3b4e203220d9f1e881b6ee" - integrity sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg== - dependencies: - call-bound "^1.0.3" - es-errors "^1.3.0" - get-intrinsic "^1.2.6" - -glob-parent@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob@^6.0.1: - version "6.0.4" - resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" - integrity sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A== - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "2 || 3" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: - version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^8.0.3: - version "8.1.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" - integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^5.0.1" - once "^1.3.0" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globalthis@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" - integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== - dependencies: - define-properties "^1.2.1" - gopd "^1.0.1" - -globby@^11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" - -gopd@^1.0.1, gopd@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" - integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== - -graceful-fs@^4.1.11, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9: - version "4.2.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" - integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== - -graphemer@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" - integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== - -has-bigints@^1.0.2: - version "1.1.0" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.1.0.tgz#28607e965ac967e03cd2a2c70a2636a1edad49fe" - integrity sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" - integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== - dependencies: - es-define-property "^1.0.0" - -has-proto@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.2.0.tgz#5de5a6eabd95fdffd9818b43055e8065e39fe9d5" - integrity sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ== - dependencies: - dunder-proto "^1.0.0" - -has-symbols@^1.0.3, has-symbols@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" - integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== - -has-tostringtag@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" - integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== - dependencies: - has-symbols "^1.0.3" - -hasown@^2.0.0, hasown@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" - integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== - dependencies: - function-bind "^1.1.2" - -hermes-estree@0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.12.0.tgz#8a289f9aee854854422345e6995a48613bac2ca8" - integrity sha512-+e8xR6SCen0wyAKrMT3UD0ZCCLymKhRgjEB5sS28rKiFir/fXgLoeRilRUssFCILmGHb+OvHDUlhxs0+IEyvQw== - -hermes-parser@0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.12.0.tgz#114dc26697cfb41a6302c215b859b74224383773" - integrity sha512-d4PHnwq6SnDLhYl3LHNHvOg7nQ6rcI7QVil418REYksv0Mh3cEkHDcuhGxNQ3vgnLSLl4QSvDrFCwQNYdpWlzw== - dependencies: - hermes-estree "0.12.0" - -hermes-profile-transformer@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/hermes-profile-transformer/-/hermes-profile-transformer-0.0.6.tgz#bd0f5ecceda80dd0ddaae443469ab26fb38fc27b" - integrity sha512-cnN7bQUm65UWOy6cbGcCcZ3rpwW8Q/j4OP5aWRhEry4Z2t2aR1cjrbp0BS+KiBN0smvP1caBgAuxutvyvJILzQ== - dependencies: - source-map "^0.7.3" - -html-escaper@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" - integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== - -http-errors@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" - integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== - dependencies: - depd "2.0.0" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses "2.0.1" - toidentifier "1.0.1" - -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - -ieee754@^1.1.13: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -ignore@^5.0.5, ignore@^5.2.0: - version "5.3.2" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" - integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== - -image-size@^1.0.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/image-size/-/image-size-1.2.0.tgz#312af27a2ff4ff58595ad00b9344dd684c910df6" - integrity sha512-4S8fwbO6w3GeCVN6OPtA9I5IGKkcDMPcKndtUlpJuCwu7JLjtj7JZpwqLuyY2nrmQT3AWsCJLSKPsc2mPBSl3w== - dependencies: - queue "6.0.2" - -import-fresh@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" - integrity sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg== - dependencies: - caller-path "^2.0.0" - resolve-from "^3.0.0" - -import-local@^3.0.2: - version "3.2.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" - integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== - dependencies: - pkg-dir "^4.2.0" - resolve-cwd "^3.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -ini@^1.3.4: - version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== - -internal-slot@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.1.0.tgz#1eac91762947d2f7056bc838d93e13b2e9604961" - integrity sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw== - dependencies: - es-errors "^1.3.0" - hasown "^2.0.2" - side-channel "^1.1.0" - -invariant@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - -is-array-buffer@^3.0.4, is-array-buffer@^3.0.5: - version "3.0.5" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz#65742e1e687bd2cc666253068fd8707fe4d44280" - integrity sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A== - dependencies: - call-bind "^1.0.8" - call-bound "^1.0.3" - get-intrinsic "^1.2.6" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== - -is-async-function@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.1.1.tgz#3e69018c8e04e73b738793d020bfe884b9fd3523" - integrity sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ== - dependencies: - async-function "^1.0.0" - call-bound "^1.0.3" - get-proto "^1.0.1" - has-tostringtag "^1.0.2" - safe-regex-test "^1.1.0" - -is-bigint@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.1.0.tgz#dda7a3445df57a42583db4228682eba7c4170672" - integrity sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ== - dependencies: - has-bigints "^1.0.2" - -is-boolean-object@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.2.1.tgz#c20d0c654be05da4fbc23c562635c019e93daf89" - integrity sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng== - dependencies: - call-bound "^1.0.2" - has-tostringtag "^1.0.2" - -is-callable@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" - integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== - -is-core-module@^2.13.0, is-core-module@^2.16.0: - version "2.16.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" - integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== - dependencies: - hasown "^2.0.2" - -is-data-view@^1.0.1, is-data-view@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.2.tgz#bae0a41b9688986c2188dda6657e56b8f9e63b8e" - integrity sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw== - dependencies: - call-bound "^1.0.2" - get-intrinsic "^1.2.6" - is-typed-array "^1.1.13" - -is-date-object@^1.0.5, is-date-object@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.1.0.tgz#ad85541996fc7aa8b2729701d27b7319f95d82f7" - integrity sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg== - dependencies: - call-bound "^1.0.2" - has-tostringtag "^1.0.2" - -is-directory@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" - integrity sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw== - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== - -is-finalizationregistry@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz#eefdcdc6c94ddd0674d9c85887bf93f944a97c90" - integrity sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg== - dependencies: - call-bound "^1.0.3" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w== - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-generator-fn@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" - integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== - -is-generator-function@^1.0.10: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.1.0.tgz#bf3eeda931201394f57b5dba2800f91a238309ca" - integrity sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ== - dependencies: - call-bound "^1.0.3" - get-proto "^1.0.0" - has-tostringtag "^1.0.2" - safe-regex-test "^1.1.0" - -is-glob@^4.0.1, is-glob@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-interactive@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" - integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== - -is-map@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" - integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== - -is-number-object@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.1.1.tgz#144b21e95a1bc148205dcc2814a9134ec41b2541" - integrity sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw== - dependencies: - call-bound "^1.0.3" - has-tostringtag "^1.0.2" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-plain-obj@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" - integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== - -is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - -is-regex@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22" - integrity sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g== - dependencies: - call-bound "^1.0.2" - gopd "^1.2.0" - has-tostringtag "^1.0.2" - hasown "^2.0.2" - -is-set@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" - integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== - -is-shared-array-buffer@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz#9b67844bd9b7f246ba0708c3a93e34269c774f6f" - integrity sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A== - dependencies: - call-bound "^1.0.3" - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -is-string@^1.0.7, is-string@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.1.1.tgz#92ea3f3d5c5b6e039ca8677e5ac8d07ea773cbb9" - integrity sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA== - dependencies: - call-bound "^1.0.3" - has-tostringtag "^1.0.2" - -is-symbol@^1.0.4, is-symbol@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.1.1.tgz#f47761279f532e2b05a7024a7506dbbedacd0634" - integrity sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w== - dependencies: - call-bound "^1.0.2" - has-symbols "^1.1.0" - safe-regex-test "^1.1.0" - -is-typed-array@^1.1.13, is-typed-array@^1.1.14, is-typed-array@^1.1.15: - version "1.1.15" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.15.tgz#4bfb4a45b61cee83a5a46fba778e4e8d59c0ce0b" - integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ== - dependencies: - which-typed-array "^1.1.16" - -is-unicode-supported@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" - integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== - -is-weakmap@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" - integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== - -is-weakref@^1.0.2, is-weakref@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.1.0.tgz#47e3472ae95a63fa9cf25660bcf0c181c39770ef" - integrity sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q== - dependencies: - call-bound "^1.0.2" - -is-weakset@^2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.4.tgz#c9f5deb0bc1906c6d6f1027f284ddf459249daca" - integrity sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ== - dependencies: - call-bound "^1.0.3" - get-intrinsic "^1.2.6" - -is-wsl@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" - integrity sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw== - -isarray@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== - -istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" - integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== - -istanbul-lib-instrument@^5.0.4: - version "5.2.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" - integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== - dependencies: - "@babel/core" "^7.12.3" - "@babel/parser" "^7.14.7" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.2.0" - semver "^6.3.0" - -istanbul-lib-instrument@^6.0.0: - version "6.0.3" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" - integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== - dependencies: - "@babel/core" "^7.23.9" - "@babel/parser" "^7.23.9" - "@istanbuljs/schema" "^0.1.3" - istanbul-lib-coverage "^3.2.0" - semver "^7.5.4" - -istanbul-lib-report@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" - integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== - dependencies: - istanbul-lib-coverage "^3.0.0" - make-dir "^4.0.0" - supports-color "^7.1.0" - -istanbul-lib-source-maps@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" - integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== - dependencies: - debug "^4.1.1" - istanbul-lib-coverage "^3.0.0" - source-map "^0.6.1" - -istanbul-reports@^3.1.3: - version "3.1.7" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" - integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - -iterator.prototype@^1.1.4: - version "1.1.5" - resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.5.tgz#12c959a29de32de0aa3bbbb801f4d777066dae39" - integrity sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g== - dependencies: - define-data-property "^1.1.4" - es-object-atoms "^1.0.0" - get-intrinsic "^1.2.6" - get-proto "^1.0.0" - has-symbols "^1.1.0" - set-function-name "^2.0.2" - -jest-changed-files@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" - integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== - dependencies: - execa "^5.0.0" - jest-util "^29.7.0" - p-limit "^3.1.0" - -jest-circus@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" - integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== - dependencies: - "@jest/environment" "^29.7.0" - "@jest/expect" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - dedent "^1.0.0" - is-generator-fn "^2.0.0" - jest-each "^29.7.0" - jest-matcher-utils "^29.7.0" - jest-message-util "^29.7.0" - jest-runtime "^29.7.0" - jest-snapshot "^29.7.0" - jest-util "^29.7.0" - p-limit "^3.1.0" - pretty-format "^29.7.0" - pure-rand "^6.0.0" - slash "^3.0.0" - stack-utils "^2.0.3" - -jest-cli@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" - integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== - dependencies: - "@jest/core" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/types" "^29.6.3" - chalk "^4.0.0" - create-jest "^29.7.0" - exit "^0.1.2" - import-local "^3.0.2" - jest-config "^29.7.0" - jest-util "^29.7.0" - jest-validate "^29.7.0" - yargs "^17.3.1" - -jest-config@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" - integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== - dependencies: - "@babel/core" "^7.11.6" - "@jest/test-sequencer" "^29.7.0" - "@jest/types" "^29.6.3" - babel-jest "^29.7.0" - chalk "^4.0.0" - ci-info "^3.2.0" - deepmerge "^4.2.2" - glob "^7.1.3" - graceful-fs "^4.2.9" - jest-circus "^29.7.0" - jest-environment-node "^29.7.0" - jest-get-type "^29.6.3" - jest-regex-util "^29.6.3" - jest-resolve "^29.7.0" - jest-runner "^29.7.0" - jest-util "^29.7.0" - jest-validate "^29.7.0" - micromatch "^4.0.4" - parse-json "^5.2.0" - pretty-format "^29.7.0" - slash "^3.0.0" - strip-json-comments "^3.1.1" - -jest-diff@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" - integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== - dependencies: - chalk "^4.0.0" - diff-sequences "^29.6.3" - jest-get-type "^29.6.3" - pretty-format "^29.7.0" - -jest-docblock@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" - integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== - dependencies: - detect-newline "^3.0.0" - -jest-each@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" - integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== - dependencies: - "@jest/types" "^29.6.3" - chalk "^4.0.0" - jest-get-type "^29.6.3" - jest-util "^29.7.0" - pretty-format "^29.7.0" - -jest-environment-node@^29.2.1, jest-environment-node@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" - integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== - dependencies: - "@jest/environment" "^29.7.0" - "@jest/fake-timers" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - jest-mock "^29.7.0" - jest-util "^29.7.0" - -jest-get-type@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" - integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== - -jest-haste-map@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" - integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== - dependencies: - "@jest/types" "^29.6.3" - "@types/graceful-fs" "^4.1.3" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.9" - jest-regex-util "^29.6.3" - jest-util "^29.7.0" - jest-worker "^29.7.0" - micromatch "^4.0.4" - walker "^1.0.8" - optionalDependencies: - fsevents "^2.3.2" - -jest-leak-detector@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" - integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== - dependencies: - jest-get-type "^29.6.3" - pretty-format "^29.7.0" - -jest-matcher-utils@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" - integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== - dependencies: - chalk "^4.0.0" - jest-diff "^29.7.0" - jest-get-type "^29.6.3" - pretty-format "^29.7.0" - -jest-message-util@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" - integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== - dependencies: - "@babel/code-frame" "^7.12.13" - "@jest/types" "^29.6.3" - "@types/stack-utils" "^2.0.0" - chalk "^4.0.0" - graceful-fs "^4.2.9" - micromatch "^4.0.4" - pretty-format "^29.7.0" - slash "^3.0.0" - stack-utils "^2.0.3" - -jest-mock@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" - integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== - dependencies: - "@jest/types" "^29.6.3" - "@types/node" "*" - jest-util "^29.7.0" - -jest-pnp-resolver@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" - integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== - -jest-regex-util@^27.0.6: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95" - integrity sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg== - -jest-regex-util@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" - integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== - -jest-resolve-dependencies@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" - integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== - dependencies: - jest-regex-util "^29.6.3" - jest-snapshot "^29.7.0" - -jest-resolve@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" - integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== - dependencies: - chalk "^4.0.0" - graceful-fs "^4.2.9" - jest-haste-map "^29.7.0" - jest-pnp-resolver "^1.2.2" - jest-util "^29.7.0" - jest-validate "^29.7.0" - resolve "^1.20.0" - resolve.exports "^2.0.0" - slash "^3.0.0" - -jest-runner@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" - integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== - dependencies: - "@jest/console" "^29.7.0" - "@jest/environment" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - chalk "^4.0.0" - emittery "^0.13.1" - graceful-fs "^4.2.9" - jest-docblock "^29.7.0" - jest-environment-node "^29.7.0" - jest-haste-map "^29.7.0" - jest-leak-detector "^29.7.0" - jest-message-util "^29.7.0" - jest-resolve "^29.7.0" - jest-runtime "^29.7.0" - jest-util "^29.7.0" - jest-watcher "^29.7.0" - jest-worker "^29.7.0" - p-limit "^3.1.0" - source-map-support "0.5.13" - -jest-runtime@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" - integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== - dependencies: - "@jest/environment" "^29.7.0" - "@jest/fake-timers" "^29.7.0" - "@jest/globals" "^29.7.0" - "@jest/source-map" "^29.6.3" - "@jest/test-result" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - chalk "^4.0.0" - cjs-module-lexer "^1.0.0" - collect-v8-coverage "^1.0.0" - glob "^7.1.3" - graceful-fs "^4.2.9" - jest-haste-map "^29.7.0" - jest-message-util "^29.7.0" - jest-mock "^29.7.0" - jest-regex-util "^29.6.3" - jest-resolve "^29.7.0" - jest-snapshot "^29.7.0" - jest-util "^29.7.0" - slash "^3.0.0" - strip-bom "^4.0.0" - -jest-snapshot@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" - integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== - dependencies: - "@babel/core" "^7.11.6" - "@babel/generator" "^7.7.2" - "@babel/plugin-syntax-jsx" "^7.7.2" - "@babel/plugin-syntax-typescript" "^7.7.2" - "@babel/types" "^7.3.3" - "@jest/expect-utils" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" - babel-preset-current-node-syntax "^1.0.0" - chalk "^4.0.0" - expect "^29.7.0" - graceful-fs "^4.2.9" - jest-diff "^29.7.0" - jest-get-type "^29.6.3" - jest-matcher-utils "^29.7.0" - jest-message-util "^29.7.0" - jest-util "^29.7.0" - natural-compare "^1.4.0" - pretty-format "^29.7.0" - semver "^7.5.3" - -jest-util@^27.2.0: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9" - integrity sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw== - dependencies: - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - ci-info "^3.2.0" - graceful-fs "^4.2.9" - picomatch "^2.2.3" - -jest-util@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" - integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== - dependencies: - "@jest/types" "^29.6.3" - "@types/node" "*" - chalk "^4.0.0" - ci-info "^3.2.0" - graceful-fs "^4.2.9" - picomatch "^2.2.3" - -jest-validate@^29.2.1, jest-validate@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" - integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== - dependencies: - "@jest/types" "^29.6.3" - camelcase "^6.2.0" - chalk "^4.0.0" - jest-get-type "^29.6.3" - leven "^3.1.0" - pretty-format "^29.7.0" - -jest-watcher@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" - integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== - dependencies: - "@jest/test-result" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - emittery "^0.13.1" - jest-util "^29.7.0" - string-length "^4.0.1" - -jest-worker@^27.2.0: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" - integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^8.0.0" - -jest-worker@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" - integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== - dependencies: - "@types/node" "*" - jest-util "^29.7.0" - merge-stream "^2.0.0" - supports-color "^8.0.0" - -jest@^29.2.1: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" - integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== - dependencies: - "@jest/core" "^29.7.0" - "@jest/types" "^29.6.3" - import-local "^3.0.2" - jest-cli "^29.7.0" - -joi@^17.2.1: - version "17.13.3" - resolved "https://registry.yarnpkg.com/joi/-/joi-17.13.3.tgz#0f5cc1169c999b30d344366d384b12d92558bcec" - integrity sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA== - dependencies: - "@hapi/hoek" "^9.3.0" - "@hapi/topo" "^5.1.0" - "@sideway/address" "^4.1.5" - "@sideway/formula" "^3.0.1" - "@sideway/pinpoint" "^2.0.0" - -js-message@1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/js-message/-/js-message-1.0.7.tgz#fbddd053c7a47021871bb8b2c95397cc17c20e47" - integrity sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA== - -js-queue@2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/js-queue/-/js-queue-2.0.2.tgz#0be590338f903b36c73d33c31883a821412cd482" - integrity sha512-pbKLsbCfi7kriM3s1J4DDCo7jQkI58zPLHi0heXPzPlj0hjUsm+FesPUbE0DSbIVIK503A36aUBoCN7eMFedkA== - dependencies: - easy-stack "^1.0.1" - -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsc-android@^250231.0.0: - version "250231.0.0" - resolved "https://registry.yarnpkg.com/jsc-android/-/jsc-android-250231.0.0.tgz#91720f8df382a108872fa4b3f558f33ba5e95262" - integrity sha512-rS46PvsjYmdmuz1OAWXY/1kCYG7pnf1TBqeTiOJr1iDz7s5DLxxC9n/ZMknLDxzYzNVfI7R95MH10emSSG1Wuw== - -jsc-safe-url@^0.2.2: - version "0.2.4" - resolved "https://registry.yarnpkg.com/jsc-safe-url/-/jsc-safe-url-0.2.4.tgz#141c14fbb43791e88d5dc64e85a374575a83477a" - integrity sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q== - -jscodeshift@^0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.14.0.tgz#7542e6715d6d2e8bde0b4e883f0ccea358b46881" - integrity sha512-7eCC1knD7bLUPuSCwXsMZUH51O8jIcoVyKtI6P0XM0IVzlGjckPy3FIwQlorzbN0Sg79oK+RlohN32Mqf/lrYA== - dependencies: - "@babel/core" "^7.13.16" - "@babel/parser" "^7.13.16" - "@babel/plugin-proposal-class-properties" "^7.13.0" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.13.8" - "@babel/plugin-proposal-optional-chaining" "^7.13.12" - "@babel/plugin-transform-modules-commonjs" "^7.13.8" - "@babel/preset-flow" "^7.13.13" - "@babel/preset-typescript" "^7.13.0" - "@babel/register" "^7.13.16" - babel-core "^7.0.0-bridge.0" - chalk "^4.1.2" - flow-parser "0.*" - graceful-fs "^4.2.4" - micromatch "^4.0.4" - neo-async "^2.5.0" - node-dir "^0.1.17" - recast "^0.21.0" - temp "^0.8.4" - write-file-atomic "^2.3.0" - -jsesc@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" - integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== - -jsesc@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" - integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== - -json-cycle@^1.3.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/json-cycle/-/json-cycle-1.5.0.tgz#b1f1d976eee16cef51d5f3d3b3caece3e90ba23a" - integrity sha512-GOehvd5PO2FeZ5T4c+RxobeT5a1PiGpF4u9/3+UvrMU4bhnVqzJY7hm39wg8PDCqkU91fWGH8qjWR4bn+wgq9w== - -json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - -json-parse-even-better-errors@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" - integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== - -json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" - integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== - -json5@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" - integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== - dependencies: - minimist "^1.2.0" - -json5@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" - integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== - -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== - optionalDependencies: - graceful-fs "^4.1.6" - -jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - -"jsx-ast-utils@^2.4.1 || ^3.0.0": - version "3.3.5" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a" - integrity sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ== - dependencies: - array-includes "^3.1.6" - array.prototype.flat "^1.3.1" - object.assign "^4.1.4" - object.values "^1.1.6" - -kind-of@^6.0.2: - version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== - -kleur@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" - integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== - -leven@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" - integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== - -lines-and-columns@^1.1.6: - version "1.2.4" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" - integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== - -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - -lodash.debounce@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== - -lodash.throttle@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" - integrity sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ== - -lodash@^4.17.11, lodash@^4.17.21: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -log-symbols@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" - integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== - dependencies: - chalk "^4.1.0" - is-unicode-supported "^0.1.0" - -logkitty@^0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/logkitty/-/logkitty-0.7.1.tgz#8e8d62f4085a826e8d38987722570234e33c6aa7" - integrity sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ== - dependencies: - ansi-fragments "^0.2.1" - dayjs "^1.8.15" - yargs "^15.1.0" - -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -lru-cache@^4.0.1: - version "4.1.5" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" - integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -make-dir@^2.0.0, make-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" - integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== - dependencies: - pify "^4.0.1" - semver "^5.6.0" - -make-dir@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" - integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== - dependencies: - semver "^7.5.3" - -makeerror@1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" - integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== - dependencies: - tmpl "1.0.5" - -math-intrinsics@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" - integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== - -memoize-one@^5.0.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" - integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - -merge2@^1.3.0, merge2@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -metro-babel-transformer@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.76.9.tgz#659ba481d471b5f748c31a8f9397094b629f50ec" - integrity sha512-dAnAmBqRdTwTPVn4W4JrowPolxD1MDbuU97u3MqtWZgVRvDpmr+Cqnn5oSxLQk3Uc+Zy3wkqVrB/zXNRlLDSAQ== - dependencies: - "@babel/core" "^7.20.0" - hermes-parser "0.12.0" - nullthrows "^1.1.1" - -metro-cache-key@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-cache-key/-/metro-cache-key-0.76.9.tgz#6f17f821d6f306fa9028b7e79445eb18387d03d9" - integrity sha512-ugJuYBLngHVh1t2Jj+uP9pSCQl7enzVXkuh6+N3l0FETfqjgOaSHlcnIhMPn6yueGsjmkiIfxQU4fyFVXRtSTw== - -metro-cache@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-cache/-/metro-cache-0.76.9.tgz#64326d7a8b470c3886a5e97d5e2a20acab20bc5f" - integrity sha512-W6QFEU5AJG1gH4Ltv8S2IvhmEhSDYnbPafyj5fGR3YLysdykj+olKv9B0V+YQXtcLGyY5CqpXLYUx595GdiKzA== - dependencies: - metro-core "0.76.9" - rimraf "^3.0.2" - -metro-config@0.76.9, metro-config@^0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-config/-/metro-config-0.76.9.tgz#5e60aff9d8894c1ee6bbc5de23b7c8515a0b84a3" - integrity sha512-oYyJ16PY3rprsfoi80L+gDJhFJqsKI3Pob5LKQbJpvL+gGr8qfZe1eQzYp5Xxxk9DOHKBV1xD94NB8GdT/DA8Q== - dependencies: - connect "^3.6.5" - cosmiconfig "^5.0.5" - jest-validate "^29.2.1" - metro "0.76.9" - metro-cache "0.76.9" - metro-core "0.76.9" - metro-runtime "0.76.9" - -metro-core@0.76.9, metro-core@^0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-core/-/metro-core-0.76.9.tgz#5f55f0fbde41d28957e4f3bb187d32251403f00e" - integrity sha512-DSeEr43Wrd5Q7ySfRzYzDwfV89g2OZTQDf1s3exOcLjE5fb7awoLOkA2h46ZzN8NcmbbM0cuJy6hOwF073/yRQ== - dependencies: - lodash.throttle "^4.1.1" - metro-resolver "0.76.9" - -metro-file-map@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-file-map/-/metro-file-map-0.76.9.tgz#dd3d76ec23fc0ba8cb7b3a3b8075bb09e0b5d378" - integrity sha512-7vJd8kksMDTO/0fbf3081bTrlw8SLiploeDf+vkkf0OwlrtDUWPOikfebp+MpZB2S61kamKjCNRfRkgrbPfSwg== - dependencies: - anymatch "^3.0.3" - debug "^2.2.0" - fb-watchman "^2.0.0" - graceful-fs "^4.2.4" - invariant "^2.2.4" - jest-regex-util "^27.0.6" - jest-util "^27.2.0" - jest-worker "^27.2.0" - micromatch "^4.0.4" - node-abort-controller "^3.1.1" - nullthrows "^1.1.1" - walker "^1.0.7" - optionalDependencies: - fsevents "^2.3.2" - -metro-inspector-proxy@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-inspector-proxy/-/metro-inspector-proxy-0.76.9.tgz#0d333e64a7bc9d156d712265faa7b7ae88c775e8" - integrity sha512-idIiPkb8CYshc0WZmbzwmr4B1QwsQUbpDwBzHwxE1ni27FWKWhV9CD5p+qlXZHgfwJuMRfPN+tIaLSR8+vttYg== - dependencies: - connect "^3.6.5" - debug "^2.2.0" - node-fetch "^2.2.0" - ws "^7.5.1" - yargs "^17.6.2" - -metro-minify-terser@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-minify-terser/-/metro-minify-terser-0.76.9.tgz#3f6271da74dd57179852118443b62cc8dc578aab" - integrity sha512-ju2nUXTKvh96vHPoGZH/INhSvRRKM14CbGAJXQ98+g8K5z1v3luYJ/7+dFQB202eVzJdTB2QMtBjI1jUUpooCg== - dependencies: - terser "^5.15.0" - -metro-minify-uglify@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-minify-uglify/-/metro-minify-uglify-0.76.9.tgz#e88c30c27911c053e1ee20e12077f0f4cbb154f8" - integrity sha512-MXRrM3lFo62FPISlPfTqC6n9HTEI3RJjDU5SvpE7sJFfJKLx02xXQEltsL/wzvEqK+DhRQ5DEYACTwf5W4Z3yA== - dependencies: - uglify-es "^3.1.9" - -metro-react-native-babel-preset@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.76.9.tgz#15868142122af14313429d7572c15cf01c16f077" - integrity sha512-eCBtW/UkJPDr6HlMgFEGF+964DZsUEF9RGeJdZLKWE7d/0nY3ABZ9ZAGxzu9efQ35EWRox5bDMXUGaOwUe5ikQ== - dependencies: - "@babel/core" "^7.20.0" - "@babel/plugin-proposal-async-generator-functions" "^7.0.0" - "@babel/plugin-proposal-class-properties" "^7.18.0" - "@babel/plugin-proposal-export-default-from" "^7.0.0" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.0" - "@babel/plugin-proposal-numeric-separator" "^7.0.0" - "@babel/plugin-proposal-object-rest-spread" "^7.20.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" - "@babel/plugin-proposal-optional-chaining" "^7.20.0" - "@babel/plugin-syntax-dynamic-import" "^7.8.0" - "@babel/plugin-syntax-export-default-from" "^7.0.0" - "@babel/plugin-syntax-flow" "^7.18.0" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.0.0" - "@babel/plugin-syntax-optional-chaining" "^7.0.0" - "@babel/plugin-transform-arrow-functions" "^7.0.0" - "@babel/plugin-transform-async-to-generator" "^7.20.0" - "@babel/plugin-transform-block-scoping" "^7.0.0" - "@babel/plugin-transform-classes" "^7.0.0" - "@babel/plugin-transform-computed-properties" "^7.0.0" - "@babel/plugin-transform-destructuring" "^7.20.0" - "@babel/plugin-transform-flow-strip-types" "^7.20.0" - "@babel/plugin-transform-function-name" "^7.0.0" - "@babel/plugin-transform-literals" "^7.0.0" - "@babel/plugin-transform-modules-commonjs" "^7.0.0" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.0.0" - "@babel/plugin-transform-parameters" "^7.0.0" - "@babel/plugin-transform-react-display-name" "^7.0.0" - "@babel/plugin-transform-react-jsx" "^7.0.0" - "@babel/plugin-transform-react-jsx-self" "^7.0.0" - "@babel/plugin-transform-react-jsx-source" "^7.0.0" - "@babel/plugin-transform-runtime" "^7.0.0" - "@babel/plugin-transform-shorthand-properties" "^7.0.0" - "@babel/plugin-transform-spread" "^7.0.0" - "@babel/plugin-transform-sticky-regex" "^7.0.0" - "@babel/plugin-transform-typescript" "^7.5.0" - "@babel/plugin-transform-unicode-regex" "^7.0.0" - "@babel/template" "^7.0.0" - babel-plugin-transform-flow-enums "^0.0.2" - react-refresh "^0.4.0" - -metro-react-native-babel-transformer@^0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.76.9.tgz#464aab85669ed39f7a59f1fd993a05de9543b09e" - integrity sha512-xXzHcfngSIkbQj+U7i/anFkNL0q2QVarYSzr34CFkzKLa79Rp16B8ki7z9eVVqo9W3B4TBcTXl3BipgRoOoZSQ== - dependencies: - "@babel/core" "^7.20.0" - babel-preset-fbjs "^3.4.0" - hermes-parser "0.12.0" - metro-react-native-babel-preset "0.76.9" - nullthrows "^1.1.1" - -metro-resolver@0.76.9, metro-resolver@^0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-resolver/-/metro-resolver-0.76.9.tgz#79c244784b16ca56076bc1fc816d2ba74860e882" - integrity sha512-s86ipNRas9vNR5lChzzSheF7HoaQEmzxBLzwFA6/2YcGmUCowcoyPAfs1yPh4cjMw9F1T4KlMLaiwniGE7HCyw== - -metro-runtime@0.76.9, metro-runtime@^0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-runtime/-/metro-runtime-0.76.9.tgz#f8ebe150f8896ce1aef5d7f3a52844f8b4f721fb" - integrity sha512-/5vezDpGUtA0Fv6cJg0+i6wB+QeBbvLeaw9cTSG7L76liP0b91f8vOcYzGaUbHI8pznJCCTerxRzpQ8e3/NcDw== - dependencies: - "@babel/runtime" "^7.0.0" - react-refresh "^0.4.0" - -metro-source-map@0.76.9, metro-source-map@^0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.76.9.tgz#0f976ada836717f307427d3830aea52a2ca7ed5f" - integrity sha512-q5qsMlu8EFvsT46wUUh+ao+efDsicT30zmaPATNhq+PcTawDbDgnMuUD+FT0bvxxnisU2PWl91RdzKfNc2qPQA== - dependencies: - "@babel/traverse" "^7.20.0" - "@babel/types" "^7.20.0" - invariant "^2.2.4" - metro-symbolicate "0.76.9" - nullthrows "^1.1.1" - ob1 "0.76.9" - source-map "^0.5.6" - vlq "^1.0.0" - -metro-symbolicate@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-symbolicate/-/metro-symbolicate-0.76.9.tgz#f1627ef6f73bb0c4d48c55684d3c87866a0b0920" - integrity sha512-Yyq6Ukj/IeWnGST09kRt0sBK8TwzGZWoU7YAcQlh14+AREH454Olx4wbFTpkkhUkV05CzNCvUuXQ0efFxhA1bw== - dependencies: - invariant "^2.2.4" - metro-source-map "0.76.9" - nullthrows "^1.1.1" - source-map "^0.5.6" - through2 "^2.0.1" - vlq "^1.0.0" - -metro-transform-plugins@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-transform-plugins/-/metro-transform-plugins-0.76.9.tgz#73e34f2014d3df3c336a882b13e541bceb826d37" - integrity sha512-YEQeNlOCt92I7S9A3xbrfaDfwfgcxz9PpD/1eeop3c4cO3z3Q3otYuxw0WJ/rUIW8pZfOm5XCehd+1NRbWlAaw== - dependencies: - "@babel/core" "^7.20.0" - "@babel/generator" "^7.20.0" - "@babel/template" "^7.0.0" - "@babel/traverse" "^7.20.0" - nullthrows "^1.1.1" - -metro-transform-worker@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-transform-worker/-/metro-transform-worker-0.76.9.tgz#281fad223f0447e1ff9cc44d6f7e33dfab9ab120" - integrity sha512-F69A0q0qFdJmP2Clqr6TpTSn4WTV9p5A28h5t9o+mB22ryXBZfUQ6BFBBW/6Wp2k/UtPH+oOsBfV9guiqm3d2Q== - dependencies: - "@babel/core" "^7.20.0" - "@babel/generator" "^7.20.0" - "@babel/parser" "^7.20.0" - "@babel/types" "^7.20.0" - babel-preset-fbjs "^3.4.0" - metro "0.76.9" - metro-babel-transformer "0.76.9" - metro-cache "0.76.9" - metro-cache-key "0.76.9" - metro-minify-terser "0.76.9" - metro-source-map "0.76.9" - metro-transform-plugins "0.76.9" - nullthrows "^1.1.1" - -metro@0.76.9, metro@^0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro/-/metro-0.76.9.tgz#605fddf1a54d27762ddba2f636420ae2408862df" - integrity sha512-gcjcfs0l5qIPg0lc5P7pj0x7vPJ97tan+OnEjiYLbKjR1D7Oa78CE93YUPyymUPH6q7VzlzMm1UjT35waEkZUw== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/core" "^7.20.0" - "@babel/generator" "^7.20.0" - "@babel/parser" "^7.20.0" - "@babel/template" "^7.0.0" - "@babel/traverse" "^7.20.0" - "@babel/types" "^7.20.0" - accepts "^1.3.7" - async "^3.2.2" - chalk "^4.0.0" - ci-info "^2.0.0" - connect "^3.6.5" - debug "^2.2.0" - denodeify "^1.2.1" - error-stack-parser "^2.0.6" - graceful-fs "^4.2.4" - hermes-parser "0.12.0" - image-size "^1.0.2" - invariant "^2.2.4" - jest-worker "^27.2.0" - jsc-safe-url "^0.2.2" - lodash.throttle "^4.1.1" - metro-babel-transformer "0.76.9" - metro-cache "0.76.9" - metro-cache-key "0.76.9" - metro-config "0.76.9" - metro-core "0.76.9" - metro-file-map "0.76.9" - metro-inspector-proxy "0.76.9" - metro-minify-uglify "0.76.9" - metro-react-native-babel-preset "0.76.9" - metro-resolver "0.76.9" - metro-runtime "0.76.9" - metro-source-map "0.76.9" - metro-symbolicate "0.76.9" - metro-transform-plugins "0.76.9" - metro-transform-worker "0.76.9" - mime-types "^2.1.27" - node-fetch "^2.2.0" - nullthrows "^1.1.1" - rimraf "^3.0.2" - serialize-error "^2.1.0" - source-map "^0.5.6" - strip-ansi "^6.0.0" - throat "^5.0.0" - ws "^7.5.1" - yargs "^17.6.2" - -micromatch@^4.0.4, micromatch@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" - integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== - dependencies: - braces "^3.0.3" - picomatch "^2.3.1" - -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -"mime-db@>= 1.43.0 < 2": - version "1.53.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.53.0.tgz#3cb63cd820fc29896d9d4e8c32ab4fcd74ccb447" - integrity sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg== - -mime-types@^2.1.27, mime-types@~2.1.34: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -mime@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - -mime@^2.4.1: - version "2.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" - integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -"minimatch@2 || 3", minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^5.0.1: - version "5.1.6" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" - integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== - dependencies: - brace-expansion "^2.0.1" - -minimist@^1.2.0, minimist@^1.2.6: - version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== - -mkdirp@^0.5.1, mkdirp@~0.5.1: - version "0.5.6" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" - integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== - dependencies: - minimist "^1.2.6" - -moment@^2.19.3: - version "2.30.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" - integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how== - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== - -ms@2.1.3, ms@^2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -multi-sort-stream@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/multi-sort-stream/-/multi-sort-stream-1.0.4.tgz#e4348edc9edc36e16333e531a90c0f166235cc99" - integrity sha512-hAZ8JOEQFbgdLe8HWZbb7gdZg0/yAIHF00Qfo3kd0rXFv96nXe+/bPTrKHZ2QMHugGX4FiAyET1Lt+jiB+7Qlg== - -multipipe@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-4.0.0.tgz#d302554ae664c1157dbfd1e8f98f03c517b3948a" - integrity sha512-jzcEAzFXoWwWwUbvHCNPwBlTz3WCWe/jPcXSmTfbo/VjRwRTfvLZ/bdvtiTdqCe8d4otCSsPCbhGYcX+eggpKQ== - dependencies: - duplexer2 "^0.1.2" - object-assign "^4.1.0" - -mv@~2: - version "2.1.1" - resolved "https://registry.yarnpkg.com/mv/-/mv-2.1.1.tgz#ae6ce0d6f6d5e0a4f7d893798d03c1ea9559b6a2" - integrity sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg== - dependencies: - mkdirp "~0.5.1" - ncp "~2.0.0" - rimraf "~2.4.0" - -nan@^2.14.0: - version "2.22.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.22.0.tgz#31bc433fc33213c97bad36404bb68063de604de3" - integrity sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw== - -natural-compare-lite@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" - integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== - -ncp@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" - integrity sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA== - -negotiator@0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" - integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== - -negotiator@~0.6.4: - version "0.6.4" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.4.tgz#777948e2452651c570b712dd01c23e262713fff7" - integrity sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w== - -neo-async@^2.5.0: - version "2.6.2" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" - integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== - -nocache@^3.0.1: - version "3.0.4" - resolved "https://registry.yarnpkg.com/nocache/-/nocache-3.0.4.tgz#5b37a56ec6e09fc7d401dceaed2eab40c8bfdf79" - integrity sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw== - -node-abort-controller@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.1.1.tgz#a94377e964a9a37ac3976d848cb5c765833b8548" - integrity sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ== - -node-dir@^0.1.17: - version "0.1.17" - resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5" - integrity sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg== - dependencies: - minimatch "^3.0.2" - -node-fetch@^2.2.0, node-fetch@^2.6.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" - integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== - dependencies: - whatwg-url "^5.0.0" - -node-int64@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== - -node-ipc@9.2.1: - version "9.2.1" - resolved "https://registry.yarnpkg.com/node-ipc/-/node-ipc-9.2.1.tgz#b32f66115f9d6ce841dc4ec2009d6a733f98bb6b" - integrity sha512-mJzaM6O3xHf9VT8BULvJSbdVbmHUKRNOH7zDDkCrA1/T+CVjq2WVIDfLt0azZRXpgArJtl3rtmEozrbXPZ9GaQ== - dependencies: - event-pubsub "4.3.0" - js-message "1.0.7" - js-queue "2.0.2" - -node-releases@^2.0.19: - version "2.0.19" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" - integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== - -node-stream-zip@^1.9.1: - version "1.15.0" - resolved "https://registry.yarnpkg.com/node-stream-zip/-/node-stream-zip-1.15.0.tgz#158adb88ed8004c6c49a396b50a6a5de3bca33ea" - integrity sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw== - -node-version@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/node-version/-/node-version-1.2.0.tgz#34fde3ffa8e1149bd323983479dda620e1b5060d" - integrity sha512-ma6oU4Sk0qOoKEAymVoTvk8EdXEobdS7m/mAGhDJ8Rouugho48crHBORAmy5BoOcv8wraPM6xumapQp5hl4iIQ== - -normalize-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - -nullthrows@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1" - integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw== - -ob1@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.76.9.tgz#a493e4b83a0fb39200de639804b5d06eed5599dc" - integrity sha512-g0I/OLnSxf6OrN3QjSew3bTDJCdbZoWxnh8adh1z36alwCuGF1dgDeRA25bTYSakrG5WULSaWJPOdgnf1O/oQw== - -object-assign@^4.1.0, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== - -object-inspect@^1.13.3: - version "1.13.3" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.3.tgz#f14c183de51130243d6d18ae149375ff50ea488a" - integrity sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA== - -object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object.assign@^4.1.4, object.assign@^4.1.7: - version "4.1.7" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.7.tgz#8c14ca1a424c6a561b0bb2a22f66f5049a945d3d" - integrity sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw== - dependencies: - call-bind "^1.0.8" - call-bound "^1.0.3" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - has-symbols "^1.1.0" - object-keys "^1.1.1" - -object.entries@^1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.8.tgz#bffe6f282e01f4d17807204a24f8edd823599c41" - integrity sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - -object.fromentries@^2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" - integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.2" - es-object-atoms "^1.0.0" - -object.values@^1.1.6, object.values@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.1.tgz#deed520a50809ff7f75a7cfd4bc64c7a038c6216" - integrity sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA== - dependencies: - call-bind "^1.0.8" - call-bound "^1.0.3" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - -on-finished@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" - integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== - dependencies: - ee-first "1.1.1" - -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== - dependencies: - ee-first "1.1.1" - -on-headers@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" - integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - -onetime@^5.1.0, onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -open@^6.2.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/open/-/open-6.4.0.tgz#5c13e96d0dc894686164f18965ecfe889ecfc8a9" - integrity sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg== - dependencies: - is-wsl "^1.1.0" - -ora@^5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" - integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== - dependencies: - bl "^4.1.0" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-spinners "^2.5.0" - is-interactive "^1.0.0" - is-unicode-supported "^0.1.0" - log-symbols "^4.1.0" - strip-ansi "^6.0.0" - wcwidth "^1.0.1" - -own-keys@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/own-keys/-/own-keys-1.0.1.tgz#e4006910a2bf913585289676eebd6f390cf51358" - integrity sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg== - dependencies: - get-intrinsic "^1.2.6" - object-keys "^1.1.1" - safe-push-apply "^1.0.0" - -p-limit@^2.0.0, p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-limit@^3.0.2, p-limit@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - -p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw== - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - -parse-json@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" - integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== - dependencies: - "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-even-better-errors "^2.3.0" - lines-and-columns "^1.1.6" - -parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - -path-key@^3.0.0, path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -picocolors@^1.0.0, picocolors@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" - integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== - -picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -pify@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" - integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - -pirates@^4.0.4, pirates@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" - integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== - -pkg-dir@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" - integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== - dependencies: - find-up "^3.0.0" - -pkg-dir@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - -pkg-up@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" - integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== - dependencies: - find-up "^3.0.0" - -possible-typed-array-names@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" - integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== - -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - -prettier@^2.4.1: - version "2.8.8" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" - integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== - -pretty-format@^26.5.2, pretty-format@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" - integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== - dependencies: - "@jest/types" "^26.6.2" - ansi-regex "^5.0.0" - ansi-styles "^4.0.0" - react-is "^17.0.1" - -pretty-format@^29.0.0, pretty-format@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" - integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== - dependencies: - "@jest/schemas" "^29.6.3" - ansi-styles "^5.0.0" - react-is "^18.0.0" - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - -promise-polyfill@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-6.1.0.tgz#dfa96943ea9c121fca4de9b5868cb39d3472e057" - integrity sha512-g0LWaH0gFsxovsU7R5LrrhHhWAWiHRnh1GPrhXnPgYsDkIqjRYUYSZEsej/wtleDrz5xVSIDbeKfidztp2XHFQ== - -promise@^8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/promise/-/promise-8.3.0.tgz#8cb333d1edeb61ef23869fbb8a4ea0279ab60e0a" - integrity sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg== - dependencies: - asap "~2.0.6" - -prompts@^2.0.1, prompts@^2.4.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" - integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== - dependencies: - kleur "^3.0.3" - sisteransi "^1.0.5" - -prop-types@^15.8.1: - version "15.8.1" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" - integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.13.1" - -proper-lockfile@^3.0.2: - version "3.2.0" - resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-3.2.0.tgz#89ca420eea1d55d38ca552578851460067bcda66" - integrity sha512-iMghHHXv2bsxl6NchhEaFck8tvX3F9cknEEh1SUpguUOBjN7PAAW9BLzmbc1g/mCD1gY3EE2EABBHPJfFdHFmA== - dependencies: - graceful-fs "^4.1.11" - retry "^0.12.0" - signal-exit "^3.0.2" - -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ== - -pure-rand@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" - integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== - -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -queue@6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/queue/-/queue-6.0.2.tgz#b91525283e2315c7553d2efa18d83e76432fed65" - integrity sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA== - dependencies: - inherits "~2.0.3" - -range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -react-devtools-core@^4.27.2: - version "4.28.5" - resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-4.28.5.tgz#c8442b91f068cdf0c899c543907f7f27d79c2508" - integrity sha512-cq/o30z9W2Wb4rzBefjv5fBalHU0rJGZCHAkf/RHSBWSSYwh8PlQTqqOJmgIIbBtpj27T6FIPXeomIjZtCNVqA== - dependencies: - shell-quote "^1.6.1" - ws "^7" - -"react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^18.0.0, react-is@^18.2.0: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" - integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== - -react-is@^16.13.1: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - -react-is@^17.0.1: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" - integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== - -react-native-fs@^2.20.0: - version "2.20.0" - resolved "https://registry.yarnpkg.com/react-native-fs/-/react-native-fs-2.20.0.tgz#05a9362b473bfc0910772c0acbb73a78dbc810f6" - integrity sha512-VkTBzs7fIDUiy/XajOSNk0XazFE9l+QlMAce7lGuebZcag5CnjszB+u4BdqzwaQOdcYb5wsJIsqq4kxInIRpJQ== - dependencies: - base-64 "^0.1.0" - utf8 "^3.0.0" - -react-native@^0.72.17: - version "0.72.17" - resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.72.17.tgz#54d6de38adf6e56fdde1a6b83ef9b138abae7384" - integrity sha512-k3dNe0XqoYCGGWTenbupWSj+ljW3GIfmYS5P4s3if4j0csx2YbenKgH1aJNWLp+UP7ONwfId6G+uBoUJfyMxXg== - dependencies: - "@jest/create-cache-key-function" "^29.2.1" - "@react-native-community/cli" "^11.4.1" - "@react-native-community/cli-platform-android" "^11.4.1" - "@react-native-community/cli-platform-ios" "^11.4.1" - "@react-native/assets-registry" "^0.72.0" - "@react-native/codegen" "^0.72.8" - "@react-native/gradle-plugin" "^0.72.11" - "@react-native/js-polyfills" "^0.72.1" - "@react-native/normalize-colors" "^0.72.0" - "@react-native/virtualized-lists" "^0.72.8" - abort-controller "^3.0.0" - anser "^1.4.9" - ansi-regex "^5.0.0" - base64-js "^1.1.2" - deprecated-react-native-prop-types "^4.2.3" - event-target-shim "^5.0.1" - flow-enums-runtime "^0.0.5" - invariant "^2.2.4" - jest-environment-node "^29.2.1" - jsc-android "^250231.0.0" - memoize-one "^5.0.0" - metro-runtime "^0.76.9" - metro-source-map "^0.76.9" - mkdirp "^0.5.1" - nullthrows "^1.1.1" - pretty-format "^26.5.2" - promise "^8.3.0" - react-devtools-core "^4.27.2" - react-refresh "^0.4.0" - react-shallow-renderer "^16.15.0" - regenerator-runtime "^0.13.2" - scheduler "0.24.0-canary-efb381bbf-20230505" - stacktrace-parser "^0.1.10" - use-sync-external-store "^1.0.0" - whatwg-fetch "^3.0.0" - ws "^6.2.2" - yargs "^17.6.2" - -react-refresh@^0.4.0: - version "0.4.3" - resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.4.3.tgz#966f1750c191672e76e16c2efa569150cc73ab53" - integrity sha512-Hwln1VNuGl/6bVwnd0Xdn1e84gT/8T9aYNL+HAKDArLCS7LWjwr7StE30IEYbIkx0Vi3vs+coQxe+SQDbGbbpA== - -react-shallow-renderer@^16.15.0: - version "16.15.0" - resolved "https://registry.yarnpkg.com/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz#48fb2cf9b23d23cde96708fe5273a7d3446f4457" - integrity sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA== - dependencies: - object-assign "^4.1.1" - react-is "^16.12.0 || ^17.0.0 || ^18.0.0" - -react-test-renderer@18.2.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-18.2.0.tgz#1dd912bd908ff26da5b9fca4fd1c489b9523d37e" - integrity sha512-JWD+aQ0lh2gvh4NM3bBM42Kx+XybOxCpgYK7F8ugAlpaTSnWsX+39Z4XkOykGZAHrjwwTZT3x3KxswVWxHPUqA== - dependencies: - react-is "^18.2.0" - react-shallow-renderer "^16.15.0" - scheduler "^0.23.0" - -react@^18.2.0: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" - integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== - dependencies: - loose-envify "^1.1.0" - -readable-stream@^2.0.2, readable-stream@~2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" - integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readable-stream@^3.4.0: - version "3.6.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" - integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readline@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/readline/-/readline-1.3.0.tgz#c580d77ef2cfc8752b132498060dc9793a7ac01c" - integrity sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg== - -recast@^0.21.0: - version "0.21.5" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.21.5.tgz#e8cd22bb51bcd6130e54f87955d33a2b2e57b495" - integrity sha512-hjMmLaUXAm1hIuTqOdeYObMslq/q+Xff6QE3Y2P+uoHAg2nmVlLBps2hzh1UJDdMtDTMXOFewK6ky51JQIeECg== - dependencies: - ast-types "0.15.2" - esprima "~4.0.0" - source-map "~0.6.1" - tslib "^2.0.1" - -reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9: - version "1.0.10" - resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz#c629219e78a3316d8b604c765ef68996964e7bf9" - integrity sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw== - dependencies: - call-bind "^1.0.8" - define-properties "^1.2.1" - es-abstract "^1.23.9" - es-errors "^1.3.0" - es-object-atoms "^1.0.0" - get-intrinsic "^1.2.7" - get-proto "^1.0.1" - which-builtin-type "^1.2.1" - -regenerate-unicode-properties@^10.2.0: - version "10.2.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz#626e39df8c372338ea9b8028d1f99dc3fd9c3db0" - integrity sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA== - dependencies: - regenerate "^1.4.2" - -regenerate@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" - integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== - -regenerator-runtime@^0.13.2: - version "0.13.11" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" - integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== - -regenerator-runtime@^0.14.0: - version "0.14.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" - integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== - -regenerator-transform@^0.15.2: - version "0.15.2" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz#5bbae58b522098ebdf09bca2f83838929001c7a4" - integrity sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg== - dependencies: - "@babel/runtime" "^7.8.4" - -regexp.prototype.flags@^1.5.3: - version "1.5.4" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz#1ad6c62d44a259007e55b3970e00f746efbcaa19" - integrity sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA== - dependencies: - call-bind "^1.0.8" - define-properties "^1.2.1" - es-errors "^1.3.0" - get-proto "^1.0.1" - gopd "^1.2.0" - set-function-name "^2.0.2" - -regexpu-core@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-6.2.0.tgz#0e5190d79e542bf294955dccabae04d3c7d53826" - integrity sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA== - dependencies: - regenerate "^1.4.2" - regenerate-unicode-properties "^10.2.0" - regjsgen "^0.8.0" - regjsparser "^0.12.0" - unicode-match-property-ecmascript "^2.0.0" - unicode-match-property-value-ecmascript "^2.1.0" - -regjsgen@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.8.0.tgz#df23ff26e0c5b300a6470cad160a9d090c3a37ab" - integrity sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q== - -regjsparser@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.12.0.tgz#0e846df6c6530586429377de56e0475583b088dc" - integrity sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ== - dependencies: - jsesc "~3.0.2" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== - -require-from-string@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - -require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== - -reselect@^4.0.0: - version "4.1.8" - resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.8.tgz#3f5dc671ea168dccdeb3e141236f69f02eaec524" - integrity sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ== - -resolve-cwd@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" - integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== - dependencies: - resolve-from "^5.0.0" - -resolve-from@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - integrity sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw== - -resolve-from@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" - integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== - -resolve.exports@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.3.tgz#41955e6f1b4013b7586f873749a635dea07ebe3f" - integrity sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A== - -resolve@^1.13.1, resolve@^1.14.2, resolve@^1.20.0: - version "1.22.10" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" - integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== - dependencies: - is-core-module "^2.16.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -resolve@^2.0.0-next.5: - version "2.0.0-next.5" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" - integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA== - dependencies: - is-core-module "^2.13.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - -retry@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" - integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -rimraf@~2.4.0: - version "2.4.5" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.4.5.tgz#ee710ce5d93a8fdb856fb5ea8ff0e2d75934b2da" - integrity sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ== - dependencies: - glob "^6.0.1" - -rimraf@~2.6.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -safe-array-concat@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz#c9e54ec4f603b0bbb8e7e5007a5ee7aecd1538c3" - integrity sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q== - dependencies: - call-bind "^1.0.8" - call-bound "^1.0.2" - get-intrinsic "^1.2.6" - has-symbols "^1.1.0" - isarray "^2.0.5" - -safe-buffer@5.2.1, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-json-stringify@~1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz#356e44bc98f1f93ce45df14bcd7c01cda86e0afd" - integrity sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg== - -safe-push-apply@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/safe-push-apply/-/safe-push-apply-1.0.0.tgz#01850e981c1602d398c85081f360e4e6d03d27f5" - integrity sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA== - dependencies: - es-errors "^1.3.0" - isarray "^2.0.5" - -safe-regex-test@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz#7f87dfb67a3150782eaaf18583ff5d1711ac10c1" - integrity sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw== - dependencies: - call-bound "^1.0.2" - es-errors "^1.3.0" - is-regex "^1.2.1" - -sanitize-filename@^1.6.1: - version "1.6.3" - resolved "https://registry.yarnpkg.com/sanitize-filename/-/sanitize-filename-1.6.3.tgz#755ebd752045931977e30b2025d340d7c9090378" - integrity sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg== - dependencies: - truncate-utf8-bytes "^1.0.0" - -scheduler@0.24.0-canary-efb381bbf-20230505: - version "0.24.0-canary-efb381bbf-20230505" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.24.0-canary-efb381bbf-20230505.tgz#5dddc60e29f91cd7f8b983d7ce4a99c2202d178f" - integrity sha512-ABvovCDe/k9IluqSh4/ISoq8tIJnW8euVAWYt5j/bg6dRnqwQwiGO1F/V4AyK96NGF/FB04FhOUDuWj8IKfABA== - dependencies: - loose-envify "^1.1.0" - -scheduler@^0.23.0: - version "0.23.2" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" - integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== - dependencies: - loose-envify "^1.1.0" - -semver@^5.6.0: - version "5.7.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" - integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== - -semver@^6.3.0, semver@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@^7.0.0, semver@^7.3.7, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4: - version "7.7.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.0.tgz#9c6fe61d0c6f9fa9e26575162ee5a9180361b09c" - integrity sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ== - -send@0.19.0: - version "0.19.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" - integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== - dependencies: - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "2.0.0" - mime "1.6.0" - ms "2.1.3" - on-finished "2.4.1" - range-parser "~1.2.1" - statuses "2.0.1" - -serialize-error@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-2.1.0.tgz#50b679d5635cdf84667bdc8e59af4e5b81d5f60a" - integrity sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw== - -serialize-error@^8.0.1: - version "8.1.0" - resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-8.1.0.tgz#3a069970c712f78634942ddd50fbbc0eaebe2f67" - integrity sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ== - dependencies: - type-fest "^0.20.2" - -serve-static@^1.13.1: - version "1.16.2" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" - integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== - dependencies: - encodeurl "~2.0.0" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.19.0" - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== - -set-function-length@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" - integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== - dependencies: - define-data-property "^1.1.4" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.4" - gopd "^1.0.1" - has-property-descriptors "^1.0.2" - -set-function-name@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" - integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== - dependencies: - define-data-property "^1.1.4" - es-errors "^1.3.0" - functions-have-names "^1.2.3" - has-property-descriptors "^1.0.2" - -set-proto@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/set-proto/-/set-proto-1.0.0.tgz#0760dbcff30b2d7e801fd6e19983e56da337565e" - integrity sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw== - dependencies: - dunder-proto "^1.0.1" - es-errors "^1.3.0" - es-object-atoms "^1.0.0" - -setprototypeof@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" - integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== - -shallow-clone@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" - integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== - dependencies: - kind-of "^6.0.2" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -shell-quote@^1.6.1, shell-quote@^1.7.2, shell-quote@^1.7.3: - version "1.8.2" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.2.tgz#d2d83e057959d53ec261311e9e9b8f51dcb2934a" - integrity sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA== - -side-channel-list@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" - integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== - dependencies: - es-errors "^1.3.0" - object-inspect "^1.13.3" - -side-channel-map@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" - integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== - dependencies: - call-bound "^1.0.2" - es-errors "^1.3.0" - get-intrinsic "^1.2.5" - object-inspect "^1.13.3" - -side-channel-weakmap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" - integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== - dependencies: - call-bound "^1.0.2" - es-errors "^1.3.0" - get-intrinsic "^1.2.5" - object-inspect "^1.13.3" - side-channel-map "^1.0.1" - -side-channel@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" - integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== - dependencies: - es-errors "^1.3.0" - object-inspect "^1.13.3" - side-channel-list "^1.0.0" - side-channel-map "^1.0.1" - side-channel-weakmap "^1.0.2" - -signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -sisteransi@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" - integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -slice-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - -source-map-support@0.5.13: - version "0.5.13" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" - integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-support@^0.5.16, source-map-support@~0.5.20: - version "0.5.21" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.5.6: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== - -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -source-map@^0.7.3: - version "0.7.4" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" - integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== - -stack-utils@^2.0.3: - version "2.0.6" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" - integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== - dependencies: - escape-string-regexp "^2.0.0" - -stackframe@^1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.3.4.tgz#b881a004c8c149a5e8efef37d51b16e412943310" - integrity sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw== - -stacktrace-parser@^0.1.10: - version "0.1.10" - resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a" - integrity sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg== - dependencies: - type-fest "^0.7.1" - -statuses@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" - integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== - -statuses@~1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== - -stream-chain@^2.2.5: - version "2.2.5" - resolved "https://registry.yarnpkg.com/stream-chain/-/stream-chain-2.2.5.tgz#b30967e8f14ee033c5b9a19bbe8a2cba90ba0d09" - integrity sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA== - -stream-json@^1.7.4: - version "1.9.1" - resolved "https://registry.yarnpkg.com/stream-json/-/stream-json-1.9.1.tgz#e3fec03e984a503718946c170db7d74556c2a187" - integrity sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw== - dependencies: - stream-chain "^2.2.5" - -string-length@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" - integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== - dependencies: - char-regex "^1.0.2" - strip-ansi "^6.0.0" - -string-natural-compare@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" - integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== - -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string.prototype.matchall@^4.0.12: - version "4.0.12" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz#6c88740e49ad4956b1332a911e949583a275d4c0" - integrity sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA== - dependencies: - call-bind "^1.0.8" - call-bound "^1.0.3" - define-properties "^1.2.1" - es-abstract "^1.23.6" - es-errors "^1.3.0" - es-object-atoms "^1.0.0" - get-intrinsic "^1.2.6" - gopd "^1.2.0" - has-symbols "^1.1.0" - internal-slot "^1.1.0" - regexp.prototype.flags "^1.5.3" - set-function-name "^2.0.2" - side-channel "^1.1.0" - -string.prototype.repeat@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz#e90872ee0308b29435aa26275f6e1b762daee01a" - integrity sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - -string.prototype.trim@^1.2.10: - version "1.2.10" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz#40b2dd5ee94c959b4dcfb1d65ce72e90da480c81" - integrity sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA== - dependencies: - call-bind "^1.0.8" - call-bound "^1.0.2" - define-data-property "^1.1.4" - define-properties "^1.2.1" - es-abstract "^1.23.5" - es-object-atoms "^1.0.0" - has-property-descriptors "^1.0.2" - -string.prototype.trimend@^1.0.9: - version "1.0.9" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz#62e2731272cd285041b36596054e9f66569b6942" - integrity sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ== - dependencies: - call-bind "^1.0.8" - call-bound "^1.0.2" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - -string.prototype.trimstart@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" - integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^5.0.0, strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-bom@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" - integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== - -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - -strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -strnum@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db" - integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA== - -sudo-prompt@^9.0.0: - version "9.2.1" - resolved "https://registry.yarnpkg.com/sudo-prompt/-/sudo-prompt-9.2.1.tgz#77efb84309c9ca489527a4e749f287e6bdd52afd" - integrity sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw== - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-color@^8.0.0: - version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - -telnet-client@1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/telnet-client/-/telnet-client-1.2.8.tgz#946c0dadc8daa3f19bb40a3e898cb870403a4ca4" - integrity sha512-W+w4k3QAmULVNhBVT2Fei369kGZCh/TH25M7caJAXW+hLxwoQRuw0di3cX4l0S9fgH3Mvq7u+IFMoBDpEw/eIg== - dependencies: - bluebird "^3.5.4" - -temp-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" - integrity sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ== - -temp@^0.8.4: - version "0.8.4" - resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.4.tgz#8c97a33a4770072e0a05f919396c7665a7dd59f2" - integrity sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg== - dependencies: - rimraf "~2.6.2" - -tempfile@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/tempfile/-/tempfile-2.0.0.tgz#6b0446856a9b1114d1856ffcbe509cccb0977265" - integrity sha512-ZOn6nJUgvgC09+doCEF3oB+r3ag7kUvlsXEGX069QRD60p+P3uP7XG9N2/at+EyIRGSN//ZY3LyEotA1YpmjuA== - dependencies: - temp-dir "^1.0.0" - uuid "^3.0.1" - -terser@^5.15.0: - version "5.37.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.37.0.tgz#38aa66d1cfc43d0638fab54e43ff8a4f72a21ba3" - integrity sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA== - dependencies: - "@jridgewell/source-map" "^0.3.3" - acorn "^8.8.2" - commander "^2.20.0" - source-map-support "~0.5.20" - -test-exclude@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" - integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== - dependencies: - "@istanbuljs/schema" "^0.1.2" - glob "^7.1.4" - minimatch "^3.0.4" - -throat@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" - integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== - -through2@^2.0.1: - version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" - integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - -tmpl@1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" - integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -toidentifier@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" - integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== - -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== - -trace-event-lib@^1.3.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/trace-event-lib/-/trace-event-lib-1.4.1.tgz#a749b8141650f56dcdecea760df4735f28d1ac6b" - integrity sha512-TOgFolKG8JFY+9d5EohGWMvwvteRafcyfPWWNIqcuD1W/FUvxWcy2MSCZ/beYHM63oYPHYHCd3tkbgCctHVP7w== - dependencies: - browser-process-hrtime "^1.0.0" - -truncate-utf8-bytes@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz#405923909592d56f78a5818434b0b78489ca5f2b" - integrity sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ== - dependencies: - utf8-byte-length "^1.0.1" - -tslib@^1.8.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tslib@^2.0.1: - version "2.8.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" - integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== - -tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - -type-detect@4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== - -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - -type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - -type-fest@^0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" - integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== - -typed-array-buffer@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536" - integrity sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw== - dependencies: - call-bound "^1.0.3" - es-errors "^1.3.0" - is-typed-array "^1.1.14" - -typed-array-byte-length@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz#8407a04f7d78684f3d252aa1a143d2b77b4160ce" - integrity sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg== - dependencies: - call-bind "^1.0.8" - for-each "^0.3.3" - gopd "^1.2.0" - has-proto "^1.2.0" - is-typed-array "^1.1.14" - -typed-array-byte-offset@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz#ae3698b8ec91a8ab945016108aef00d5bff12355" - integrity sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ== - dependencies: - available-typed-arrays "^1.0.7" - call-bind "^1.0.8" - for-each "^0.3.3" - gopd "^1.2.0" - has-proto "^1.2.0" - is-typed-array "^1.1.15" - reflect.getprototypeof "^1.0.9" - -typed-array-length@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.7.tgz#ee4deff984b64be1e118b0de8c9c877d5ce73d3d" - integrity sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg== - dependencies: - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - is-typed-array "^1.1.13" - possible-typed-array-names "^1.0.0" - reflect.getprototypeof "^1.0.6" - -typescript@4.8.4: - version "4.8.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" - integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== - -uglify-es@^3.1.9: - version "3.3.9" - resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" - integrity sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ== - dependencies: - commander "~2.13.0" - source-map "~0.6.1" - -unbox-primitive@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz#8d9d2c9edeea8460c7f35033a88867944934d1e2" - integrity sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw== - dependencies: - call-bound "^1.0.3" - has-bigints "^1.0.2" - has-symbols "^1.1.0" - which-boxed-primitive "^1.1.1" - -undici-types@~6.20.0: - version "6.20.0" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" - integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== - -unicode-canonical-property-names-ecmascript@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz#cb3173fe47ca743e228216e4a3ddc4c84d628cc2" - integrity sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg== - -unicode-match-property-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" - integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== - dependencies: - unicode-canonical-property-names-ecmascript "^2.0.0" - unicode-property-aliases-ecmascript "^2.0.0" - -unicode-match-property-value-ecmascript@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz#a0401aee72714598f739b68b104e4fe3a0cb3c71" - integrity sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg== - -unicode-property-aliases-ecmascript@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" - integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== - -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - -universalify@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" - integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== - -unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== - -update-browserslist-db@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz#97e9c96ab0ae7bcac08e9ae5151d26e6bc6b5580" - integrity sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg== - dependencies: - escalade "^3.2.0" - picocolors "^1.1.1" - -use-sync-external-store@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz#adbc795d8eeb47029963016cefdf89dc799fcebc" - integrity sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw== - -utf8-byte-length@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz#f9f63910d15536ee2b2d5dd4665389715eac5c1e" - integrity sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA== - -utf8@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" - integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== - -util-deprecate@^1.0.1, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== - -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== - -uuid@^3.0.1: - version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== - -v8-to-istanbul@^9.0.1: - version "9.3.0" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" - integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== - dependencies: - "@jridgewell/trace-mapping" "^0.3.12" - "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^2.0.0" - -vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== - -vlq@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/vlq/-/vlq-1.0.1.tgz#c003f6e7c0b4c1edd623fd6ee50bbc0d6a1de468" - integrity sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w== - -walker@^1.0.7, walker@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" - integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== - dependencies: - makeerror "1.0.12" - -wcwidth@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" - integrity sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg== - dependencies: - defaults "^1.0.3" - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== - -whatwg-fetch@^3.0.0: - version "3.6.20" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz#580ce6d791facec91d37c72890995a0b48d31c70" - integrity sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg== - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - -which-boxed-primitive@^1.1.0, which-boxed-primitive@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz#d76ec27df7fa165f18d5808374a5fe23c29b176e" - integrity sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA== - dependencies: - is-bigint "^1.1.0" - is-boolean-object "^1.2.1" - is-number-object "^1.1.1" - is-string "^1.1.1" - is-symbol "^1.1.1" - -which-builtin-type@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.2.1.tgz#89183da1b4907ab089a6b02029cc5d8d6574270e" - integrity sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q== - dependencies: - call-bound "^1.0.2" - function.prototype.name "^1.1.6" - has-tostringtag "^1.0.2" - is-async-function "^2.0.0" - is-date-object "^1.1.0" - is-finalizationregistry "^1.1.0" - is-generator-function "^1.0.10" - is-regex "^1.2.1" - is-weakref "^1.0.2" - isarray "^2.0.5" - which-boxed-primitive "^1.1.0" - which-collection "^1.0.2" - which-typed-array "^1.1.16" - -which-collection@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0" - integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== - dependencies: - is-map "^2.0.3" - is-set "^2.0.3" - is-weakmap "^2.0.2" - is-weakset "^2.0.3" - -which-module@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" - integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== - -which-typed-array@^1.1.16, which-typed-array@^1.1.18: - version "1.1.18" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.18.tgz#df2389ebf3fbb246a71390e90730a9edb6ce17ad" - integrity sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA== - dependencies: - available-typed-arrays "^1.0.7" - call-bind "^1.0.8" - call-bound "^1.0.3" - for-each "^0.3.3" - gopd "^1.2.0" - has-tostringtag "^1.0.2" - -which@^1.2.9, which@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -wrap-ansi@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" - integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -write-file-atomic@^2.3.0: - version "2.4.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" - integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ== - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - signal-exit "^3.0.2" - -write-file-atomic@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" - integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== - dependencies: - imurmurhash "^0.1.4" - signal-exit "^3.0.7" - -ws@^6.2.2: - version "6.2.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.3.tgz#ccc96e4add5fd6fedbc491903075c85c5a11d9ee" - integrity sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA== - dependencies: - async-limiter "~1.0.0" - -ws@^7, ws@^7.0.0, ws@^7.5.1: - version "7.5.10" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" - integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== - -xtend@~4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - -y18n@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" - integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== - -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A== - -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - -yaml@^2.2.1: - version "2.7.0" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.7.0.tgz#aef9bb617a64c937a9a748803786ad8d3ffe1e98" - integrity sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA== - -yargs-parser@^18.1.2: - version "18.1.3" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" - integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs-parser@^21.0.0, yargs-parser@^21.1.1: - version "21.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" - integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== - -yargs-unparser@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" - integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== - dependencies: - camelcase "^6.0.0" - decamelize "^4.0.0" - flat "^5.0.2" - is-plain-obj "^2.1.0" - -yargs@^15.1.0: - version "15.4.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" - integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== - dependencies: - cliui "^6.0.0" - decamelize "^1.2.0" - find-up "^4.1.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^4.2.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^18.1.2" - -yargs@^17.0.0, yargs@^17.3.1, yargs@^17.6.2: - version "17.7.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" - integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== - dependencies: - cliui "^8.0.1" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.3" - y18n "^5.0.5" - yargs-parser "^21.1.1" - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/js/react_native/ios/OnnxruntimeModule.xcodeproj/project.pbxproj b/js/react_native/ios/OnnxruntimeModule.xcodeproj/project.pbxproj index d0f6db84e51fb..079033b9194eb 100644 --- a/js/react_native/ios/OnnxruntimeModule.xcodeproj/project.pbxproj +++ b/js/react_native/ios/OnnxruntimeModule.xcodeproj/project.pbxproj @@ -273,10 +273,15 @@ "${BUILT_PRODUCTS_DIR}/React-Codegen/React_Codegen.framework", "${BUILT_PRODUCTS_DIR}/React-Core/React.framework", "${BUILT_PRODUCTS_DIR}/React-CoreModules/CoreModules.framework", + "${BUILT_PRODUCTS_DIR}/React-Fabric/React_Fabric.framework", + "${BUILT_PRODUCTS_DIR}/React-FabricImage/React_FabricImage.framework", + "${BUILT_PRODUCTS_DIR}/React-ImageManager/React_ImageManager.framework", + "${BUILT_PRODUCTS_DIR}/React-Mapbuffer/React_Mapbuffer.framework", "${BUILT_PRODUCTS_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework", "${BUILT_PRODUCTS_DIR}/React-RCTAnimation/RCTAnimation.framework", "${BUILT_PRODUCTS_DIR}/React-RCTAppDelegate/React_RCTAppDelegate.framework", "${BUILT_PRODUCTS_DIR}/React-RCTBlob/RCTBlob.framework", + "${BUILT_PRODUCTS_DIR}/React-RCTFabric/RCTFabric.framework", "${BUILT_PRODUCTS_DIR}/React-RCTImage/RCTImage.framework", "${BUILT_PRODUCTS_DIR}/React-RCTLinking/RCTLinking.framework", "${BUILT_PRODUCTS_DIR}/React-RCTNetwork/RCTNetwork.framework", @@ -284,12 +289,17 @@ "${BUILT_PRODUCTS_DIR}/React-RCTText/RCTText.framework", "${BUILT_PRODUCTS_DIR}/React-RCTVibration/RCTVibration.framework", "${BUILT_PRODUCTS_DIR}/React-cxxreact/cxxreact.framework", - "${BUILT_PRODUCTS_DIR}/React-jsc/React_jsc.framework", + "${BUILT_PRODUCTS_DIR}/React-debug/React_debug.framework", + "${BUILT_PRODUCTS_DIR}/React-graphics/React_graphics.framework", + "${BUILT_PRODUCTS_DIR}/React-hermes/reacthermes.framework", + "${BUILT_PRODUCTS_DIR}/React-jserrorhandler/React_jserrorhandler.framework", "${BUILT_PRODUCTS_DIR}/React-jsi/jsi.framework", "${BUILT_PRODUCTS_DIR}/React-jsiexecutor/jsireact.framework", "${BUILT_PRODUCTS_DIR}/React-jsinspector/jsinspector.framework", "${BUILT_PRODUCTS_DIR}/React-logger/logger.framework", + "${BUILT_PRODUCTS_DIR}/React-nativeconfig/React_nativeconfig.framework", "${BUILT_PRODUCTS_DIR}/React-perflogger/reactperflogger.framework", + "${BUILT_PRODUCTS_DIR}/React-rendererdebug/React_rendererdebug.framework", "${BUILT_PRODUCTS_DIR}/React-runtimescheduler/React_runtimescheduler.framework", "${BUILT_PRODUCTS_DIR}/React-utils/React_utils.framework", "${BUILT_PRODUCTS_DIR}/ReactCommon/ReactCommon.framework", @@ -297,6 +307,8 @@ "${BUILT_PRODUCTS_DIR}/Yoga/yoga.framework", "${BUILT_PRODUCTS_DIR}/fmt/fmt.framework", "${BUILT_PRODUCTS_DIR}/glog/glog.framework", + "${BUILT_PRODUCTS_DIR}/libevent/libevent.framework", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( @@ -306,10 +318,15 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_Codegen.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CoreModules.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_Fabric.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_FabricImage.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_ImageManager.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_Mapbuffer.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_NativeModulesApple.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTAnimation.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_RCTAppDelegate.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTBlob.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTFabric.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTImage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTLinking.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTNetwork.framework", @@ -317,12 +334,17 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTText.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTVibration.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/cxxreact.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_jsc.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_debug.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_graphics.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/reacthermes.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_jserrorhandler.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/jsi.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/jsireact.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/jsinspector.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/logger.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_nativeconfig.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/reactperflogger.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_rendererdebug.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_runtimescheduler.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React_utils.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReactCommon.framework", @@ -330,6 +352,8 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/yoga.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/fmt.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/glog.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libevent.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -395,7 +419,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -419,7 +443,7 @@ COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; - "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -443,6 +467,9 @@ "${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers/platform/ios", "${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers", "${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios", + " ${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers", + " ${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx", + " ${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers", ); "HEADER_SEARCH_PATHS[arch=*]" = ""; IPHONEOS_DEPLOYMENT_TARGET = 15.1; @@ -454,6 +481,7 @@ OTHER_LDFLAGS = "$(inherited)"; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; + USE_HERMES = true; }; name = Debug; }; @@ -461,7 +489,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -485,7 +513,7 @@ COPY_PHASE_STRIP = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -505,6 +533,9 @@ "${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers/platform/ios", "${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers", "${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios", + " ${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers", + " ${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx", + " ${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers", ); "HEADER_SEARCH_PATHS[arch=*]" = ""; IPHONEOS_DEPLOYMENT_TARGET = 15.1; @@ -515,6 +546,7 @@ OTHER_LDFLAGS = "$(inherited)"; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; + USE_HERMES = true; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/js/react_native/ios/Podfile b/js/react_native/ios/Podfile index 95e43ee369910..c252d18965ad5 100644 --- a/js/react_native/ios/Podfile +++ b/js/react_native/ios/Podfile @@ -14,16 +14,9 @@ use_frameworks! def shared config = use_native_modules! - # Flags change depending on the env values. - flags = get_default_flags() - use_react_native!( :path => config[:reactNativePath], - # Hermes is now enabled by default. Disable by setting this flag to false. - # Upcoming versions of React Native may rely on get_default_flags(), but - # we make it explicit here to aid in the React Native upgrade process. - :hermes_enabled => false, - :fabric_enabled => false, + :app_path => "#{Pod::Config.instance.installation_root}/.." ) @@ -50,5 +43,4 @@ post_install do |installer| installer, :mac_catalyst_enabled => false ) - __apply_Xcode_12_5_M1_post_install_workaround(installer) end \ No newline at end of file diff --git a/js/react_native/lib/backend.ts b/js/react_native/lib/backend.ts index 854a7ffd9a6ab..edc28c2e43de9 100644 --- a/js/react_native/lib/backend.ts +++ b/js/react_native/lib/backend.ts @@ -66,6 +66,13 @@ class OnnxruntimeSessionHandler implements InferenceSessionHandler { inputNames: string[]; outputNames: string[]; + get inputMetadata(): readonly InferenceSession.ValueMetadata[] { + throw new Error('Getting model metadata is currently not implemented for react-native backend.'); + } + get outputMetadata(): readonly InferenceSession.ValueMetadata[] { + throw new Error('Getting model metadata is currently not implemented for react-native backend.'); + } + constructor(pathOrBuffer: string | Uint8Array) { this.#inferenceSession = binding; this.#pathOrBuffer = pathOrBuffer; diff --git a/js/react_native/lib/version.ts b/js/react_native/lib/version.ts index 475dfe0d4888b..8ec54c0bd22dc 100644 --- a/js/react_native/lib/version.ts +++ b/js/react_native/lib/version.ts @@ -4,4 +4,4 @@ // This file is generated by /js/scripts/update-version.ts // Do not modify file content manually. -export const version = '1.21.0'; +export const version = '1.22.0'; diff --git a/js/react_native/package-lock.json b/js/react_native/package-lock.json new file mode 100644 index 0000000000000..0c797ca2a2a16 --- /dev/null +++ b/js/react_native/package-lock.json @@ -0,0 +1,8808 @@ +{ + "name": "onnxruntime-react-native", + "version": "1.22.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "onnxruntime-react-native", + "version": "1.22.0", + "license": "MIT", + "dependencies": { + "buffer": "^6.0.3", + "onnxruntime-common": "file:../common" + }, + "devDependencies": { + "@react-native/typescript-config": "0.73.1", + "@types/react": "^18.2.6", + "pod-install": "^0.1.36", + "prettier": "^2.8.8", + "react": "^18.2.0", + "react-native": "^0.73.11", + "react-native-builder-bob": "^0.37.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "../common": { + "name": "onnxruntime-common", + "version": "1.22.0", + "license": "MIT", + "devDependencies": { + "typedoc": "^0.25.7" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@ampproject/remapping/node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", + "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/core/node_modules/debug": { + "version": "4.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/core/node_modules/ms": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/generator": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.9.tgz", + "integrity": "sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.26.9", + "@babel/types": "^7.26.9", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", + "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.26.5", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.26.9.tgz", + "integrity": "sha512-ubbUqCofvxPRurw5L8WTsCLSkQiVpov4Qx0WMA+jUN+nXBK8ADPlJO1grkFw5CWKC5+sZSOfuGMdX1aI1iT9Sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/helper-replace-supers": "^7.26.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/traverse": "^7.26.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.26.3.tgz", + "integrity": "sha512-G7ZRb40uUgdKOQqPLjfD12ZmGA54PzqDFUv2BKImnC9QIfGhIHKvVML0oN8IUiDq4iRqpq74ABpvOaerfWdong==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "regexpu-core": "^6.2.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz", + "integrity": "sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", + "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", + "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-wrap-function": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz", + "integrity": "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/traverse": "^7.26.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", + "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz", + "integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.9.tgz", + "integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.9" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz", + "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz", + "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz", + "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz", + "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.17.12", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-remap-async-to-generator": "^7.16.8", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-export-default-from": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.25.9.tgz", + "integrity": "sha512-ykqgwNfSnNOB+C8fV5X4mG3AVmvu+WVxcaU9xHHtBb7PCrPeweMmPjGsn8eMaeJg6SJuoUuZENeeSWaarWqonQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", + "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", + "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-default-from": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.25.9.tgz", + "integrity": "sha512-9MhJ/SMTsVqsd69GyQg89lYR4o9T+oDGv5F6IsigxxqFVOyR/IflDLYP8WDI1l8fkhNGGktqkvL5qwNCtGEpgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.26.0.tgz", + "integrity": "sha512-B+O2DnPc0iG+YXFqOxv2WNuNU97ToWjOomUQ78DouOENWUaM5sVrmet9mcomUGQFwpJd//gvUagXBSdzO1fRKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz", + "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", + "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", + "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.26.8.tgz", + "integrity": "sha512-He9Ej2X7tNf2zdKMAGOsmg2MrFc+hfoAhd3po4cWfo/NWjzEAKa0oQruj1ROVUdl0e6fb6/kE/G3SSxE0lRJOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/helper-remap-async-to-generator": "^7.25.9", + "@babel/traverse": "^7.26.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", + "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.26.5.tgz", + "integrity": "sha512-chuTSY+hq09+/f5lMj8ZSYgCFpppV2CbYrhNFJ1BFoXpiWPnnAb7R0MqrafCpN8E1+YRrtM1MXZHJdIx8B6rMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.26.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", + "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", + "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz", + "integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", + "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/traverse": "^7.25.9", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", + "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/template": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", + "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", + "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", + "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz", + "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz", + "integrity": "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz", + "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.26.5.tgz", + "integrity": "sha512-eGK26RsbIkYUns3Y8qKl362juDDYK+wEdPGHGrhzUl6CewZFo55VZ7hg+CyMFU4dd5QQakBN86nBMpRsFpRvbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/plugin-syntax-flow": "^7.26.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.26.9.tgz", + "integrity": "sha512-Hry8AusVm8LW5BVFgiyUReuoGzPUpdHQQqJY5bZnbbf+ngOHWuCuYFKw/BqaaWlvEUrF91HMhDtEaI1hZzNbLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", + "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz", + "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", + "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz", + "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", + "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", + "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", + "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", + "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", + "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", + "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.26.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.26.6.tgz", + "integrity": "sha512-CKW8Vu+uUZneQCPtXmSBUC6NCAUdya26hWCElAWh5mVSlSRsmiCPUUDKb3Z0szng1hiAJa098Hkhg9o4SE35Qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.26.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz", + "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz", + "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", + "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz", + "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", + "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz", + "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz", + "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", + "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.9.tgz", + "integrity": "sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz", + "integrity": "sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.25.9.tgz", + "integrity": "sha512-9mj6rm7XVYs4mdLIpbZnHOYdpW42uoiBCTVowg7sP1thUOiANgMb4UtpRivR0pp5iL+ocvUv7X4mZgFRpJEzGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.9.tgz", + "integrity": "sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.9.tgz", + "integrity": "sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.25.9.tgz", + "integrity": "sha512-KQ/Takk3T8Qzj5TppkS1be588lkbTp5uj7w6a0LeQaTMSckU/wK0oJ/pih+T690tkgI5jfmg2TqDJvd41Sj1Cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz", + "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz", + "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", + "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.26.9.tgz", + "integrity": "sha512-Jf+8y9wXQbbxvVYTM8gO5oEF2POdNji0NMltEkG7FtmzD9PVz7/lxpqSdTvwsjTMU5HIHuDVNf2SOxLkWi+wPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.26.5", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", + "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", + "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", + "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-strict-mode": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-strict-mode/-/plugin-transform-strict-mode-7.25.9.tgz", + "integrity": "sha512-DplEwkN9xt6XCz/4oC9l8FJGn7LnOGPU7v08plq+OclMT55zAR9lkX7QIbQ9XscvvJNYpLUfYO4IYz/7JGkbXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.26.8.tgz", + "integrity": "sha512-OmGDL5/J0CJPJZTHZbi2XpO0tyT2Ia7fzpW5GURwdtp2X3fMmN8au/ej6peC/T33/+CRiIpA8Krse8hFGVmT5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.26.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.26.7.tgz", + "integrity": "sha512-jfoTXXZTgGg36BmhqT3cAYK5qkmqvJpvNrPhaK/52Vgjhw4Rq29s9UqpWWV0D6yuRmgiFH/BUVlkl96zJWqnaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.26.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.8.tgz", + "integrity": "sha512-bME5J9AC8ChwA7aEPJ6zym3w7aObZULHhbNLU0bKUhKsAkylkzUdq+0kdymh9rzi8nlNFl2bmldFBCKNJBUpuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-syntax-typescript": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", + "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz", + "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", + "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz", + "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.9.tgz", + "integrity": "sha512-vX3qPGE8sEKEAZCWk05k3cpTAE3/nOYca++JA+Rd0z2NCNzabmYvEiSShKzm10zdquOIAVXsy2Ei/DTW34KlKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.26.8", + "@babel/helper-compilation-targets": "^7.26.5", + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.26.0", + "@babel/plugin-syntax-import-attributes": "^7.26.0", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.25.9", + "@babel/plugin-transform-async-generator-functions": "^7.26.8", + "@babel/plugin-transform-async-to-generator": "^7.25.9", + "@babel/plugin-transform-block-scoped-functions": "^7.26.5", + "@babel/plugin-transform-block-scoping": "^7.25.9", + "@babel/plugin-transform-class-properties": "^7.25.9", + "@babel/plugin-transform-class-static-block": "^7.26.0", + "@babel/plugin-transform-classes": "^7.25.9", + "@babel/plugin-transform-computed-properties": "^7.25.9", + "@babel/plugin-transform-destructuring": "^7.25.9", + "@babel/plugin-transform-dotall-regex": "^7.25.9", + "@babel/plugin-transform-duplicate-keys": "^7.25.9", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-dynamic-import": "^7.25.9", + "@babel/plugin-transform-exponentiation-operator": "^7.26.3", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-for-of": "^7.26.9", + "@babel/plugin-transform-function-name": "^7.25.9", + "@babel/plugin-transform-json-strings": "^7.25.9", + "@babel/plugin-transform-literals": "^7.25.9", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", + "@babel/plugin-transform-member-expression-literals": "^7.25.9", + "@babel/plugin-transform-modules-amd": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.26.3", + "@babel/plugin-transform-modules-systemjs": "^7.25.9", + "@babel/plugin-transform-modules-umd": "^7.25.9", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-new-target": "^7.25.9", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.26.6", + "@babel/plugin-transform-numeric-separator": "^7.25.9", + "@babel/plugin-transform-object-rest-spread": "^7.25.9", + "@babel/plugin-transform-object-super": "^7.25.9", + "@babel/plugin-transform-optional-catch-binding": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9", + "@babel/plugin-transform-private-methods": "^7.25.9", + "@babel/plugin-transform-private-property-in-object": "^7.25.9", + "@babel/plugin-transform-property-literals": "^7.25.9", + "@babel/plugin-transform-regenerator": "^7.25.9", + "@babel/plugin-transform-regexp-modifiers": "^7.26.0", + "@babel/plugin-transform-reserved-words": "^7.25.9", + "@babel/plugin-transform-shorthand-properties": "^7.25.9", + "@babel/plugin-transform-spread": "^7.25.9", + "@babel/plugin-transform-sticky-regex": "^7.25.9", + "@babel/plugin-transform-template-literals": "^7.26.8", + "@babel/plugin-transform-typeof-symbol": "^7.26.7", + "@babel/plugin-transform-unicode-escapes": "^7.25.9", + "@babel/plugin-transform-unicode-property-regex": "^7.25.9", + "@babel/plugin-transform-unicode-regex": "^7.25.9", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.11.0", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.40.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-flow": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.25.9.tgz", + "integrity": "sha512-EASHsAhE+SSlEzJ4bzfusnXSHiU+JfAYzj+jbw2vgQKgq5HrUr8qs+vgtiEL5dOH6sEweI+PNt2D7AqrDSHyqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-transform-flow-strip-types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.26.3.tgz", + "integrity": "sha512-Nl03d6T9ky516DGK2YMxrTqvnpUW63TnJMOMonj+Zae0JiPC5BC9xPMSL6L8fiSpA5vP88qfygavVQvnLp+6Cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-transform-react-display-name": "^7.25.9", + "@babel/plugin-transform-react-jsx": "^7.25.9", + "@babel/plugin-transform-react-jsx-development": "^7.25.9", + "@babel/plugin-transform-react-pure-annotations": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.26.0.tgz", + "integrity": "sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-typescript": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/register": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.25.9.tgz", + "integrity": "sha512-8D43jXtGsYmEeDvm4MWHYUpWf8iiXgWYx3fW7E7Wb7Oe6FWqJPl5K6TuFW0dOwNZzEE5rjlaSJYH9JjrUKJszA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "find-cache-dir": "^2.0.0", + "make-dir": "^2.1.0", + "pirates": "^4.0.6", + "source-map-support": "^0.5.16" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz", + "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime/node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/template": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz", + "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/parser": "^7.26.9", + "@babel/types": "^7.26.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.9.tgz", + "integrity": "sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.9", + "@babel/parser": "^7.26.9", + "@babel/template": "^7.26.9", + "@babel/types": "^7.26.9", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/traverse/node_modules/ms": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/types": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.9.tgz", + "integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@isaacs/ttlcache": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz", + "integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/@jest/create-cache-key-function": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz", + "integrity": "sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/create-cache-key-function/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/create-cache-key-function/node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@react-native-community/cli": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-12.3.7.tgz", + "integrity": "sha512-7+mOhk+3+X3BjSJZZvYrDJynA00gPYTlvT28ZjiLlbuVGfqfNiBKaxuF7rty+gjjpch4iKGvLhIhSN5cuOsdHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native-community/cli-clean": "12.3.7", + "@react-native-community/cli-config": "12.3.7", + "@react-native-community/cli-debugger-ui": "12.3.7", + "@react-native-community/cli-doctor": "12.3.7", + "@react-native-community/cli-hermes": "12.3.7", + "@react-native-community/cli-plugin-metro": "12.3.7", + "@react-native-community/cli-server-api": "12.3.7", + "@react-native-community/cli-tools": "12.3.7", + "@react-native-community/cli-types": "12.3.7", + "chalk": "^4.1.2", + "commander": "^9.4.1", + "deepmerge": "^4.3.0", + "execa": "^5.0.0", + "find-up": "^4.1.0", + "fs-extra": "^8.1.0", + "graceful-fs": "^4.1.3", + "prompts": "^2.4.2", + "semver": "^7.5.2" + }, + "bin": { + "react-native": "build/bin.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native-community/cli-clean": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-12.3.7.tgz", + "integrity": "sha512-BCYW77QqyxfhiMEBOoHyciJRNV6Rhz1RvclReIKnCA9wAwmoJBeu4Mu+AwiECA2bUITX16fvPt3NwDsSd1jwfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native-community/cli-tools": "12.3.7", + "chalk": "^4.1.2", + "execa": "^5.0.0" + } + }, + "node_modules/@react-native-community/cli-config": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-12.3.7.tgz", + "integrity": "sha512-IU2UhO9yj1rEBNhHWGzIXpPDzha4hizLP/PUOrhR4BUf6RVPUWEp+e1PXNGR0qjIf6esu7OC7t6mLOhH0NUJEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native-community/cli-tools": "12.3.7", + "chalk": "^4.1.2", + "cosmiconfig": "^5.1.0", + "deepmerge": "^4.3.0", + "glob": "^7.1.3", + "joi": "^17.2.1" + } + }, + "node_modules/@react-native-community/cli-debugger-ui": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-12.3.7.tgz", + "integrity": "sha512-UHUFrRdcjWSCdWG9KIp2QjuRIahBQnb9epnQI7JCq6NFbFHYfEI4rI7msjMn+gG8/tSwKTV2PTPuPmZ5wWlE7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "serve-static": "^1.13.1" + } + }, + "node_modules/@react-native-community/cli-doctor": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-12.3.7.tgz", + "integrity": "sha512-gCamZztRoAyhciuQPqdz4Xe4t3gOdNsaADNd+rva+Rx8W2PoPeNv60i7/et06wlsn6B6Sh0/hMiAftJbiHDFkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native-community/cli-config": "12.3.7", + "@react-native-community/cli-platform-android": "12.3.7", + "@react-native-community/cli-platform-ios": "12.3.7", + "@react-native-community/cli-tools": "12.3.7", + "chalk": "^4.1.2", + "command-exists": "^1.2.8", + "deepmerge": "^4.3.0", + "envinfo": "^7.10.0", + "execa": "^5.0.0", + "hermes-profile-transformer": "^0.0.6", + "node-stream-zip": "^1.9.1", + "ora": "^5.4.1", + "semver": "^7.5.2", + "strip-ansi": "^5.2.0", + "wcwidth": "^1.0.1", + "yaml": "^2.2.1" + } + }, + "node_modules/@react-native-community/cli-doctor/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@react-native-community/cli-doctor/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@react-native-community/cli-doctor/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@react-native-community/cli-doctor/node_modules/yaml": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", + "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@react-native-community/cli-hermes": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-12.3.7.tgz", + "integrity": "sha512-ezzeiSKjRXK2+i1AAe7NhhN9CEHrgtRmTn2MAdBpE++N8fH5EQZgxFcGgGdwGvns2fm9ivyyeVnI5eAYwvM+jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native-community/cli-platform-android": "12.3.7", + "@react-native-community/cli-tools": "12.3.7", + "chalk": "^4.1.2", + "hermes-profile-transformer": "^0.0.6" + } + }, + "node_modules/@react-native-community/cli-platform-android": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-12.3.7.tgz", + "integrity": "sha512-mOltF3cpjNdJb3WSFwEHc1GH4ibCcnOvQ34OdWyblKy9ijuvG5SjNTlYR/UW/CURaDi3OUKAhxQMTY5d27bzGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native-community/cli-tools": "12.3.7", + "chalk": "^4.1.2", + "execa": "^5.0.0", + "fast-xml-parser": "^4.2.4", + "glob": "^7.1.3", + "logkitty": "^0.7.1" + } + }, + "node_modules/@react-native-community/cli-platform-ios": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-12.3.7.tgz", + "integrity": "sha512-2WnVsMH4ORZIhBm/5nCms1NeeKG4KarNC7PMLmrXWXB/bibDcaNsjrJiqnmCUcpTEvTQTokRfoO7Aj6NM0Cqow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native-community/cli-tools": "12.3.7", + "chalk": "^4.1.2", + "execa": "^5.0.0", + "fast-xml-parser": "^4.0.12", + "glob": "^7.1.3", + "ora": "^5.4.1" + } + }, + "node_modules/@react-native-community/cli-plugin-metro": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-12.3.7.tgz", + "integrity": "sha512-ahEw0Vfnv2Nv/jdZ2QDuGjQ9l2SczO4lXjb3ubu5vEYNLyTw3jYsLMK6iES7YQ/ApQmKdG476HU1O9uZdpaYPg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@react-native-community/cli-server-api": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-12.3.7.tgz", + "integrity": "sha512-LYETs3CCjrLn1ZU0kYv44TywiIl5IPFHZGeXhAh2TtgOk4mo3kvXxECDil9CdO3bmDra6qyiG61KHvzr8IrHdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native-community/cli-debugger-ui": "12.3.7", + "@react-native-community/cli-tools": "12.3.7", + "compression": "^1.7.1", + "connect": "^3.6.5", + "errorhandler": "^1.5.1", + "nocache": "^3.0.1", + "pretty-format": "^26.6.2", + "serve-static": "^1.13.1", + "ws": "^7.5.1" + } + }, + "node_modules/@react-native-community/cli-server-api/node_modules/@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@react-native-community/cli-server-api/node_modules/@types/yargs": { + "version": "15.0.19", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.19.tgz", + "integrity": "sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@react-native-community/cli-server-api/node_modules/pretty-format": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@react-native-community/cli-tools": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-12.3.7.tgz", + "integrity": "sha512-7NL/1/i+wzd4fBr/FSr3ypR05tiU/Kv9l/M1sL1c6jfcDtWXAL90R161gQkQFK7shIQ8Idp0dQX1rq49tSyfQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "appdirsjs": "^1.2.4", + "chalk": "^4.1.2", + "find-up": "^5.0.0", + "mime": "^2.4.1", + "node-fetch": "^2.6.0", + "open": "^6.2.0", + "ora": "^5.4.1", + "semver": "^7.5.2", + "shell-quote": "^1.7.3", + "sudo-prompt": "^9.0.0" + } + }, + "node_modules/@react-native-community/cli-tools/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@react-native-community/cli-tools/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@react-native-community/cli-tools/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@react-native-community/cli-tools/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@react-native-community/cli-tools/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@react-native-community/cli-types": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-12.3.7.tgz", + "integrity": "sha512-NFtUMyIrNfi3A5C1cjVKDVvYHvvOF7MnOMwdD8jm2NQKewQJrehKBh1eMuykKdqhWyZmuemD4KKhL8f4FxgG0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "joi": "^17.2.1" + } + }, + "node_modules/@react-native-community/cli/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@react-native/assets-registry": { + "version": "0.73.1", + "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.73.1.tgz", + "integrity": "sha512-2FgAbU7uKM5SbbW9QptPPZx8N9Ke2L7bsHb+EhAanZjFZunA9PaYtyjUQ1s7HD+zDVqOQIvjkpXSv7Kejd2tqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/babel-plugin-codegen": { + "version": "0.73.4", + "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.73.4.tgz", + "integrity": "sha512-XzRd8MJGo4Zc5KsphDHBYJzS1ryOHg8I2gOZDAUCGcwLFhdyGu1zBNDJYH2GFyDrInn9TzAbRIf3d4O+eltXQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native/codegen": "0.73.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/babel-preset": { + "version": "0.73.21", + "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.73.21.tgz", + "integrity": "sha512-WlFttNnySKQMeujN09fRmrdWqh46QyJluM5jdtDNrkl/2Hx6N4XeDUGhABvConeK95OidVO7sFFf7sNebVXogA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.20.0", + "@babel/plugin-proposal-async-generator-functions": "^7.0.0", + "@babel/plugin-proposal-class-properties": "^7.18.0", + "@babel/plugin-proposal-export-default-from": "^7.0.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.0", + "@babel/plugin-proposal-numeric-separator": "^7.0.0", + "@babel/plugin-proposal-object-rest-spread": "^7.20.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.0.0", + "@babel/plugin-proposal-optional-chaining": "^7.20.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-export-default-from": "^7.0.0", + "@babel/plugin-syntax-flow": "^7.18.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0", + "@babel/plugin-syntax-optional-chaining": "^7.0.0", + "@babel/plugin-transform-arrow-functions": "^7.0.0", + "@babel/plugin-transform-async-to-generator": "^7.20.0", + "@babel/plugin-transform-block-scoping": "^7.0.0", + "@babel/plugin-transform-classes": "^7.0.0", + "@babel/plugin-transform-computed-properties": "^7.0.0", + "@babel/plugin-transform-destructuring": "^7.20.0", + "@babel/plugin-transform-flow-strip-types": "^7.20.0", + "@babel/plugin-transform-function-name": "^7.0.0", + "@babel/plugin-transform-literals": "^7.0.0", + "@babel/plugin-transform-modules-commonjs": "^7.0.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.0.0", + "@babel/plugin-transform-parameters": "^7.0.0", + "@babel/plugin-transform-private-methods": "^7.22.5", + "@babel/plugin-transform-private-property-in-object": "^7.22.11", + "@babel/plugin-transform-react-display-name": "^7.0.0", + "@babel/plugin-transform-react-jsx": "^7.0.0", + "@babel/plugin-transform-react-jsx-self": "^7.0.0", + "@babel/plugin-transform-react-jsx-source": "^7.0.0", + "@babel/plugin-transform-runtime": "^7.0.0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0", + "@babel/plugin-transform-spread": "^7.0.0", + "@babel/plugin-transform-sticky-regex": "^7.0.0", + "@babel/plugin-transform-typescript": "^7.5.0", + "@babel/plugin-transform-unicode-regex": "^7.0.0", + "@babel/template": "^7.0.0", + "@react-native/babel-plugin-codegen": "0.73.4", + "babel-plugin-transform-flow-enums": "^0.0.2", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@react-native/codegen": { + "version": "0.73.3", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.73.3.tgz", + "integrity": "sha512-sxslCAAb8kM06vGy9Jyh4TtvjhcP36k/rvj2QE2Jdhdm61KvfafCATSIsOfc0QvnduWFcpXUPvAVyYwuv7PYDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.0", + "flow-parser": "^0.206.0", + "glob": "^7.1.1", + "invariant": "^2.2.4", + "jscodeshift": "^0.14.0", + "mkdirp": "^0.5.1", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@babel/preset-env": "^7.1.6" + } + }, + "node_modules/@react-native/community-cli-plugin": { + "version": "0.73.18", + "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.73.18.tgz", + "integrity": "sha512-RN8piDh/eF+QT6YYmrj3Zd9uiaDsRY/kMT0FYR42j8/M/boE4hs4Xn0u91XzT8CAkU9q/ilyo3wJsXIJo2teww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native-community/cli-server-api": "12.3.7", + "@react-native-community/cli-tools": "12.3.7", + "@react-native/dev-middleware": "0.73.8", + "@react-native/metro-babel-transformer": "0.73.15", + "chalk": "^4.0.0", + "execa": "^5.1.1", + "metro": "^0.80.3", + "metro-config": "^0.80.3", + "metro-core": "^0.80.3", + "node-fetch": "^2.2.0", + "readline": "^1.3.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/debugger-frontend": { + "version": "0.73.3", + "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.73.3.tgz", + "integrity": "sha512-RgEKnWuoo54dh7gQhV7kvzKhXZEhpF9LlMdZolyhGxHsBqZ2gXdibfDlfcARFFifPIiaZ3lXuOVVa4ei+uPgTw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/dev-middleware": { + "version": "0.73.8", + "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.73.8.tgz", + "integrity": "sha512-oph4NamCIxkMfUL/fYtSsE+JbGOnrlawfQ0kKtDQ5xbOjPKotKoXqrs1eGwozNKv7FfQ393stk1by9a6DyASSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@isaacs/ttlcache": "^1.4.1", + "@react-native/debugger-frontend": "0.73.3", + "chrome-launcher": "^0.15.2", + "chromium-edge-launcher": "^1.0.0", + "connect": "^3.6.5", + "debug": "^2.2.0", + "node-fetch": "^2.2.0", + "open": "^7.0.3", + "serve-static": "^1.13.1", + "temp-dir": "^2.0.0", + "ws": "^6.2.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/dev-middleware/node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@react-native/dev-middleware/node_modules/ws": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", + "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/@react-native/gradle-plugin": { + "version": "0.73.5", + "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.73.5.tgz", + "integrity": "sha512-Orrn8J/kqzEuXudl96XcZk84ZcdIpn1ojjwGSuaSQSXNcCYbOXyt0RwtW5kjCqjgSzGnOMsJNZc5FDXHVq/WzA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/js-polyfills": { + "version": "0.73.1", + "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.73.1.tgz", + "integrity": "sha512-ewMwGcumrilnF87H4jjrnvGZEaPFCAC4ebraEK+CurDDmwST/bIicI4hrOAv+0Z0F7DEK4O4H7r8q9vH7IbN4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/metro-babel-transformer": { + "version": "0.73.15", + "resolved": "https://registry.npmjs.org/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.73.15.tgz", + "integrity": "sha512-LlkSGaXCz+xdxc9819plmpsl4P4gZndoFtpjN3GMBIu6f7TBV0GVbyJAU4GE8fuAWPVSVL5ArOcdkWKSbI1klw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.20.0", + "@react-native/babel-preset": "0.73.21", + "hermes-parser": "0.15.0", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@react-native/normalize-colors": { + "version": "0.73.2", + "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.73.2.tgz", + "integrity": "sha512-bRBcb2T+I88aG74LMVHaKms2p/T8aQd8+BZ7LuuzXlRfog1bMWWn/C5i0HVuvW4RPtXQYgIlGiXVDy9Ir1So/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@react-native/typescript-config": { + "version": "0.73.1", + "resolved": "https://registry.npmjs.org/@react-native/typescript-config/-/typescript-config-0.73.1.tgz", + "integrity": "sha512-7Wrmdp972ZO7xvDid+xRGtvX6xz47cpGj7Y7VKlUhSVFFqbOGfB5WCpY1vMr6R/fjl+Og2fRw+TETN2+JnJi0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@react-native/virtualized-lists": { + "version": "0.73.4", + "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.73.4.tgz", + "integrity": "sha512-HpmLg1FrEiDtrtAbXiwCgXFYyloK/dOIPIuWW3fsqukwJEWAiTzm1nXGJ7xPU5XTHiWZ4sKup5Ebaj8z7iyWog==", + "dev": true, + "license": "MIT", + "dependencies": { + "invariant": "^2.2.4", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react-native": "*" + } + }, + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/node": { + "version": "17.0.35", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.7.tgz", + "integrity": "sha512-KUnDCJF5+AiZd8owLIeVHqmW9yM4sqmDVf2JRJiBMFkGvkoZ4/WyV2lL4zVsoinmRS/W3FeEdZLEWFRofnT2FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/anser": { + "version": "1.4.10", + "dev": true, + "license": "MIT" + }, + "node_modules/ansi-fragments": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ansi-fragments/-/ansi-fragments-0.2.1.tgz", + "integrity": "sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "colorette": "^1.0.7", + "slice-ansi": "^2.0.0", + "strip-ansi": "^5.0.0" + } + }, + "node_modules/ansi-fragments/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-fragments/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/appdirsjs": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/appdirsjs/-/appdirsjs-1.2.7.tgz", + "integrity": "sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "1.0.10", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ast-types": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.15.2.tgz", + "integrity": "sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/async-limiter": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/babel-core": { + "version": "7.0.0-bridge.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", + "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-module-resolver": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-5.0.2.tgz", + "integrity": "sha512-9KtaCazHee2xc0ibfqsDeamwDps6FZNo5S0Q81dUqEuFzVwPhcT4J5jOqIVvgCA3Q/wO9hKYxN/Ds3tIsp5ygg==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-babel-config": "^2.1.1", + "glob": "^9.3.3", + "pkg-up": "^3.1.0", + "reselect": "^4.1.7", + "resolve": "^1.22.8" + } + }, + "node_modules/babel-plugin-module-resolver/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/babel-plugin-module-resolver/node_modules/glob": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/babel-plugin-module-resolver/node_modules/minimatch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.12", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.12.tgz", + "integrity": "sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.3", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz", + "integrity": "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.3", + "core-js-compat": "^3.40.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.3.tgz", + "integrity": "sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.3" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-transform-flow-enums": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-enums/-/babel-plugin-transform-flow-enums-0.0.2.tgz", + "integrity": "sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-flow": "^7.12.1" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.24.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", + "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/caller-callsite/node_modules/callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "caller-callsite": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001704", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001704.tgz", + "integrity": "sha512-+L2IgBbV6gXB4ETf0keSvLr7JUrRVbIaB/lrQ1+z8mRcQiisG5k+lG6O4n6Y5q6f5EuNfaYXKgymucphlEXQew==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chrome-launcher": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz", + "integrity": "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0" + }, + "bin": { + "print-chrome-path": "bin/print-chrome-path.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/chromium-edge-launcher": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-1.0.0.tgz", + "integrity": "sha512-pgtgjNKZ7i5U++1g1PWv75umkHvhVTDOQIZ+sjeUX9483S7Y6MUvO0lrd7ShGlQlFHMN4SwKTCq/X8hWrbv2KA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0", + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "node_modules/chromium-edge-launcher/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true, + "license": "MIT" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz", + "integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.0.2", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/core-js-compat": { + "version": "3.41.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.41.0.tgz", + "integrity": "sha512-RFsU9LySVue9RTwdDVX/T0e2Y6jRYWXERKElIjpuEOEnxaXffI0X7RUwVzfYLfzuLXSNJDYoRYUAmRUcyln20A==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.24.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "license": "MIT", + "dependencies": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cosmiconfig/node_modules/import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cosmiconfig/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cosmiconfig/node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/csstype": { + "version": "3.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/del": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "dev": true, + "license": "MIT", + "dependencies": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/denodeify": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz", + "integrity": "sha512-KNTihKNmQENUZeKu5fzfpzRqR5S2VMp4gl9RFHiWzj9DfvYQPMJ6XHKNaQxaGCXwPk6y9yme3aUoaiAe+KX+vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/deprecated-react-native-prop-types": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-5.0.0.tgz", + "integrity": "sha512-cIK8KYiiGVOFsKdPMmm1L3tA/Gl+JopXL6F5+C7x39MyPsQYnP57Im/D6bNUzcborD7fcMwiwZqcBdBXXZucYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native/normalize-colors": "^0.73.0", + "invariant": "^2.2.4", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.118", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.118.tgz", + "integrity": "sha512-yNDUus0iultYyVoEFLnQeei7LOQkL8wg8GQpkPCRrOlJXlcCwa6eGKZkxQ9ciHsqZyYbj8Jd94X1CTPzGm+uIA==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/envinfo": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", + "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", + "dev": true, + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/errorhandler": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.5.1.tgz", + "integrity": "sha512-rcOwbfvP1WTViVoUjcfZicVzjhjTuhSMntHh6mW3IrEiyE6mJyXvsToJUJGlGlw/2xU9P5whlWNGlIDVeCiT4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "~1.3.7", + "escape-html": "~1.0.3" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.2.tgz", + "integrity": "sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-xml-parser": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.3.tgz", + "integrity": "sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "strnum": "^1.1.1" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-babel-config": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-2.1.2.tgz", + "integrity": "sha512-ZfZp1rQyp4gyuxqt1ZqjFGVeVBvmpURMqdIWXbPRfB97Bf6BzdK/xSIbylEINzQ0kB5tlDQfn9HkNXXWsqTqLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "json5": "^2.2.3" + } + }, + "node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/find-cache-dir/node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flow-enums-runtime": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz", + "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==", + "dev": true, + "license": "MIT" + }, + "node_modules/flow-parser": { + "version": "0.206.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.206.0.tgz", + "integrity": "sha512-HVzoK3r6Vsg+lKvlIZzaWNBVai+FXTX1wdYhz/wVlH13tb/gOdLXmlTqy6odmTBhT5UoWUbq0k8263Qhr9d88w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-extra/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hermes-estree": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.15.0.tgz", + "integrity": "sha512-lLYvAd+6BnOqWdnNbP/Q8xfl8LOGw4wVjfrNd9Gt8eoFzhNBRVD95n4l2ksfMVOoxuVyegs85g83KS9QOsxbVQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.15.0.tgz", + "integrity": "sha512-Q1uks5rjZlE9RjMMjSUCkGrEIPI5pKJILeCtK1VmTj7U4pf3wVPoo+cxfu+s4cBAPy2JzikIIdCZgBoR6x7U1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.15.0" + } + }, + "node_modules/hermes-profile-transformer": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/hermes-profile-transformer/-/hermes-profile-transformer-0.0.6.tgz", + "integrity": "sha512-cnN7bQUm65UWOy6cbGcCcZ3rpwW8Q/j4OP5aWRhEry4Z2t2aR1cjrbp0BS+KiBN0smvP1caBgAuxutvyvJILzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "source-map": "^0.7.3" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/hermes-profile-transformer/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-size": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.0.tgz", + "integrity": "sha512-4S8fwbO6w3GeCVN6OPtA9I5IGKkcDMPcKndtUlpJuCwu7JLjtj7JZpwqLuyY2nrmQT3AWsCJLSKPsc2mPBSl3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "queue": "6.0.2" + }, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=16.x" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "dev": true, + "license": "ISC" + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-git-dirty": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-git-dirty/-/is-git-dirty-2.0.2.tgz", + "integrity": "sha512-U3YCo+GKR/rDsY7r0v/LBICbQwsx859tDQnAT+v0E/zCDeWbQ1TUt1FtyExeyik7VIJlYOLHCIifLdz71HDalg==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^4.0.3", + "is-git-repository": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/is-git-dirty/node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/is-git-dirty/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-git-repository": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-git-repository/-/is-git-repository-2.0.0.tgz", + "integrity": "sha512-HDO50CG5suIAcmqG4F1buqVXEZRPn+RaXIn9pFKq/947FBo2bCRwK7ZluEVZOy99a4IQyqsjbKEpAiOXCccOHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^4.0.3", + "is-absolute": "^1.0.0" + } + }, + "node_modules/is-git-repository/node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/is-git-repository/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unc-path": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "unc-path-regex": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/joi": { + "version": "17.13.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", + "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsc-android": { + "version": "250231.0.0", + "resolved": "https://registry.npmjs.org/jsc-android/-/jsc-android-250231.0.0.tgz", + "integrity": "sha512-rS46PvsjYmdmuz1OAWXY/1kCYG7pnf1TBqeTiOJr1iDz7s5DLxxC9n/ZMknLDxzYzNVfI7R95MH10emSSG1Wuw==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/jsc-safe-url": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/jsc-safe-url/-/jsc-safe-url-0.2.4.tgz", + "integrity": "sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==", + "dev": true, + "license": "0BSD" + }, + "node_modules/jscodeshift": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.14.0.tgz", + "integrity": "sha512-7eCC1knD7bLUPuSCwXsMZUH51O8jIcoVyKtI6P0XM0IVzlGjckPy3FIwQlorzbN0Sg79oK+RlohN32Mqf/lrYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.13.16", + "@babel/parser": "^7.13.16", + "@babel/plugin-proposal-class-properties": "^7.13.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.8", + "@babel/plugin-proposal-optional-chaining": "^7.13.12", + "@babel/plugin-transform-modules-commonjs": "^7.13.8", + "@babel/preset-flow": "^7.13.13", + "@babel/preset-typescript": "^7.13.0", + "@babel/register": "^7.13.16", + "babel-core": "^7.0.0-bridge.0", + "chalk": "^4.1.2", + "flow-parser": "0.*", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.4", + "neo-async": "^2.5.0", + "node-dir": "^0.1.17", + "recast": "^0.21.0", + "temp": "^0.8.4", + "write-file-atomic": "^2.3.0" + }, + "bin": { + "jscodeshift": "bin/jscodeshift.js" + }, + "peerDependencies": { + "@babel/preset-env": "^7.1.6" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lighthouse-logger": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz", + "integrity": "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^2.6.9", + "marky": "^1.2.2" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/logkitty": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/logkitty/-/logkitty-0.7.1.tgz", + "integrity": "sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-fragments": "^0.2.1", + "dayjs": "^1.8.15", + "yargs": "^15.1.0" + }, + "bin": { + "logkitty": "bin/logkitty.js" + } + }, + "node_modules/logkitty/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/logkitty/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/logkitty/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/logkitty/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/logkitty/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/marky": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.5.tgz", + "integrity": "sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/memoize-one": { + "version": "5.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/metro": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.80.12.tgz", + "integrity": "sha512-1UsH5FzJd9quUsD1qY+zUG4JY3jo3YEMxbMYH9jT6NK3j4iORhlwTK8fYTfAUBhDKjgLfKjAh7aoazNE23oIRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@babel/core": "^7.20.0", + "@babel/generator": "^7.20.0", + "@babel/parser": "^7.20.0", + "@babel/template": "^7.0.0", + "@babel/traverse": "^7.20.0", + "@babel/types": "^7.20.0", + "accepts": "^1.3.7", + "chalk": "^4.0.0", + "ci-info": "^2.0.0", + "connect": "^3.6.5", + "debug": "^2.2.0", + "denodeify": "^1.2.1", + "error-stack-parser": "^2.0.6", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "hermes-parser": "0.23.1", + "image-size": "^1.0.2", + "invariant": "^2.2.4", + "jest-worker": "^29.6.3", + "jsc-safe-url": "^0.2.2", + "lodash.throttle": "^4.1.1", + "metro-babel-transformer": "0.80.12", + "metro-cache": "0.80.12", + "metro-cache-key": "0.80.12", + "metro-config": "0.80.12", + "metro-core": "0.80.12", + "metro-file-map": "0.80.12", + "metro-resolver": "0.80.12", + "metro-runtime": "0.80.12", + "metro-source-map": "0.80.12", + "metro-symbolicate": "0.80.12", + "metro-transform-plugins": "0.80.12", + "metro-transform-worker": "0.80.12", + "mime-types": "^2.1.27", + "nullthrows": "^1.1.1", + "serialize-error": "^2.1.0", + "source-map": "^0.5.6", + "strip-ansi": "^6.0.0", + "throat": "^5.0.0", + "ws": "^7.5.10", + "yargs": "^17.6.2" + }, + "bin": { + "metro": "src/cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-babel-transformer": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.80.12.tgz", + "integrity": "sha512-YZziRs0MgA3pzCkkvOoQRXjIoVjvrpi/yRlJnObyIvMP6lFdtyG4nUGIwGY9VXnBvxmXD6mPY2e+NSw6JAyiRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.20.0", + "flow-enums-runtime": "^0.0.6", + "hermes-parser": "0.23.1", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-babel-transformer/node_modules/hermes-estree": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.23.1.tgz", + "integrity": "sha512-eT5MU3f5aVhTqsfIReZ6n41X5sYn4IdQL0nvz6yO+MMlPxw49aSARHLg/MSehQftyjnrE8X6bYregzSumqc6cg==", + "dev": true, + "license": "MIT" + }, + "node_modules/metro-babel-transformer/node_modules/hermes-parser": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.23.1.tgz", + "integrity": "sha512-oxl5h2DkFW83hT4DAUJorpah8ou4yvmweUzLJmmr6YV2cezduCdlil1AvU/a/xSsAFo4WUcNA4GoV5Bvq6JffA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.23.1" + } + }, + "node_modules/metro-cache": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.80.12.tgz", + "integrity": "sha512-p5kNHh2KJ0pbQI/H7ZBPCEwkyNcSz7OUkslzsiIWBMPQGFJ/xArMwkV7I+GJcWh+b4m6zbLxE5fk6fqbVK1xGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "exponential-backoff": "^3.1.1", + "flow-enums-runtime": "^0.0.6", + "metro-core": "0.80.12" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-cache-key": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.80.12.tgz", + "integrity": "sha512-o4BspKnugg/pE45ei0LGHVuBJXwRgruW7oSFAeSZvBKA/sGr0UhOGY3uycOgWInnS3v5yTTfiBA9lHlNRhsvGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-config": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.80.12.tgz", + "integrity": "sha512-4rwOWwrhm62LjB12ytiuR5NgK1ZBNr24/He8mqCsC+HXZ+ATbrewLNztzbAZHtFsrxP4D4GLTGgh96pCpYLSAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "connect": "^3.6.5", + "cosmiconfig": "^5.0.5", + "flow-enums-runtime": "^0.0.6", + "jest-validate": "^29.6.3", + "metro": "0.80.12", + "metro-cache": "0.80.12", + "metro-core": "0.80.12", + "metro-runtime": "0.80.12" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-config/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/metro-config/node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/metro-config/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/metro-config/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/metro-config/node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/metro-config/node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/metro-config/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/metro-config/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/metro-core": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.80.12.tgz", + "integrity": "sha512-QqdJ/yAK+IpPs2HU/h5v2pKEdANBagSsc6DRSjnwSyJsCoHlmyJKCaCJ7KhWGx+N4OHxh37hoA8fc2CuZbx0Fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "lodash.throttle": "^4.1.1", + "metro-resolver": "0.80.12" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-file-map": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.80.12.tgz", + "integrity": "sha512-sYdemWSlk66bWzW2wp79kcPMzwuG32x1ZF3otI0QZTmrnTaaTiGyhE66P1z6KR4n2Eu5QXiABa6EWbAQv0r8bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "^3.0.3", + "debug": "^2.2.0", + "fb-watchman": "^2.0.0", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "invariant": "^2.2.4", + "jest-worker": "^29.6.3", + "micromatch": "^4.0.4", + "node-abort-controller": "^3.1.1", + "nullthrows": "^1.1.1", + "walker": "^1.0.7" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/metro-file-map/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/metro-file-map/node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/metro-file-map/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/metro-file-map/node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/metro-file-map/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/metro-minify-terser": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.80.12.tgz", + "integrity": "sha512-muWzUw3y5k+9083ZoX9VaJLWEV2Jcgi+Oan0Mmb/fBNMPqP9xVDuy4pOMn/HOiGndgfh/MK7s4bsjkyLJKMnXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "terser": "^5.15.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-resolver": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.80.12.tgz", + "integrity": "sha512-PR24gYRZnYHM3xT9pg6BdbrGbM/Cu1TcyIFBVlAk7qDAuHkUNQ1nMzWumWs+kwSvtd9eZGzHoucGJpTUEeLZAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-runtime": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.80.12.tgz", + "integrity": "sha512-LIx7+92p5rpI0i6iB4S4GBvvLxStNt6fF0oPMaUd1Weku7jZdfkCZzmrtDD9CSQ6EPb0T9NUZoyXIxlBa3wOCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-source-map": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.80.12.tgz", + "integrity": "sha512-o+AXmE7hpvM8r8MKsx7TI21/eerYYy2DCDkWfoBkv+jNkl61khvDHlQn0cXZa6lrcNZiZkl9oHSMcwLLIrFmpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.20.0", + "@babel/types": "^7.20.0", + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-symbolicate": "0.80.12", + "nullthrows": "^1.1.1", + "ob1": "0.80.12", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-source-map/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/metro-symbolicate": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.80.12.tgz", + "integrity": "sha512-/dIpNdHksXkGHZXARZpL7doUzHqSNxgQ8+kQGxwpJuHnDhGkENxB5PS2QBaTDdEcmyTMjS53CN1rl9n1gR6fmw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-source-map": "0.80.12", + "nullthrows": "^1.1.1", + "source-map": "^0.5.6", + "through2": "^2.0.1", + "vlq": "^1.0.0" + }, + "bin": { + "metro-symbolicate": "src/index.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-symbolicate/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/metro-transform-plugins": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.80.12.tgz", + "integrity": "sha512-WQWp00AcZvXuQdbjQbx1LzFR31IInlkCDYJNRs6gtEtAyhwpMMlL2KcHmdY+wjDO9RPcliZ+Xl1riOuBecVlPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.20.0", + "@babel/generator": "^7.20.0", + "@babel/template": "^7.0.0", + "@babel/traverse": "^7.20.0", + "flow-enums-runtime": "^0.0.6", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro-transform-worker": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.80.12.tgz", + "integrity": "sha512-KAPFN1y3eVqEbKLx1I8WOarHPqDMUa8WelWxaJCNKO/yHCP26zELeqTJvhsQup+8uwB6EYi/sp0b6TGoh6lOEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.20.0", + "@babel/generator": "^7.20.0", + "@babel/parser": "^7.20.0", + "@babel/types": "^7.20.0", + "flow-enums-runtime": "^0.0.6", + "metro": "0.80.12", + "metro-babel-transformer": "0.80.12", + "metro-cache": "0.80.12", + "metro-cache-key": "0.80.12", + "metro-minify-terser": "0.80.12", + "metro-source-map": "0.80.12", + "metro-transform-plugins": "0.80.12", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/metro/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/metro/node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/metro/node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/metro/node_modules/hermes-estree": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.23.1.tgz", + "integrity": "sha512-eT5MU3f5aVhTqsfIReZ6n41X5sYn4IdQL0nvz6yO+MMlPxw49aSARHLg/MSehQftyjnrE8X6bYregzSumqc6cg==", + "dev": true, + "license": "MIT" + }, + "node_modules/metro/node_modules/hermes-parser": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.23.1.tgz", + "integrity": "sha512-oxl5h2DkFW83hT4DAUJorpah8ou4yvmweUzLJmmr6YV2cezduCdlil1AvU/a/xSsAFo4WUcNA4GoV5Bvq6JffA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.23.1" + } + }, + "node_modules/metro/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/metro/node_modules/jest-util/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/metro/node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/metro/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/metro/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/metro/node_modules/throat": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", + "dev": true, + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nocache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/nocache/-/nocache-3.0.4.tgz", + "integrity": "sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-dir": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimatch": "^3.0.2" + }, + "engines": { + "node": ">= 0.10.5" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-stream-zip": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.15.0.tgz", + "integrity": "sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/antelle" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/nullthrows": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", + "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ob1": { + "version": "0.80.12", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.80.12.tgz", + "integrity": "sha512-VMArClVT6LkhUGpnuEoBuyjG9rzUyEzg4PDkav6wK1cLhOK02gPCYFxoiB4mqVnrMhDpIzJcrGNAMVi9P+hXrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/onnxruntime-common": { + "resolved": "../common", + "link": true + }, + "node_modules/open": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz", + "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^1.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/open/node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pod-install": { + "version": "0.1.36", + "dev": true, + "license": "MIT", + "bin": { + "pod-install": "build/index.js" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "asap": "~2.0.6" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "~2.0.3" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-devtools-core": { + "version": "4.28.5", + "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.28.5.tgz", + "integrity": "sha512-cq/o30z9W2Wb4rzBefjv5fBalHU0rJGZCHAkf/RHSBWSSYwh8PlQTqqOJmgIIbBtpj27T6FIPXeomIjZtCNVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shell-quote": "^1.6.1", + "ws": "^7" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/react-native": { + "version": "0.73.11", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.73.11.tgz", + "integrity": "sha512-yvQIX+ZXOHMFnhmwZ1fBpRI/53k+iLN8DxVf24Fx4ABU63RGAYfyCZC0/3W+5OUVx4KSIZUv4Tv+/NGIieBOwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/create-cache-key-function": "^29.6.3", + "@react-native-community/cli": "12.3.7", + "@react-native-community/cli-platform-android": "12.3.7", + "@react-native-community/cli-platform-ios": "12.3.7", + "@react-native/assets-registry": "0.73.1", + "@react-native/codegen": "0.73.3", + "@react-native/community-cli-plugin": "0.73.18", + "@react-native/gradle-plugin": "0.73.5", + "@react-native/js-polyfills": "0.73.1", + "@react-native/normalize-colors": "0.73.2", + "@react-native/virtualized-lists": "0.73.4", + "abort-controller": "^3.0.0", + "anser": "^1.4.9", + "ansi-regex": "^5.0.0", + "base64-js": "^1.5.1", + "chalk": "^4.0.0", + "deprecated-react-native-prop-types": "^5.0.0", + "event-target-shim": "^5.0.1", + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "jest-environment-node": "^29.6.3", + "jsc-android": "^250231.0.0", + "memoize-one": "^5.0.0", + "metro-runtime": "^0.80.3", + "metro-source-map": "^0.80.3", + "mkdirp": "^0.5.1", + "nullthrows": "^1.1.1", + "pretty-format": "^26.5.2", + "promise": "^8.3.0", + "react-devtools-core": "^4.27.7", + "react-refresh": "^0.14.0", + "react-shallow-renderer": "^16.15.0", + "regenerator-runtime": "^0.13.2", + "scheduler": "0.24.0-canary-efb381bbf-20230505", + "stacktrace-parser": "^0.1.10", + "whatwg-fetch": "^3.0.0", + "ws": "^6.2.2", + "yargs": "^17.6.2" + }, + "bin": { + "react-native": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "18.2.0" + } + }, + "node_modules/react-native-builder-bob": { + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/react-native-builder-bob/-/react-native-builder-bob-0.37.0.tgz", + "integrity": "sha512-CkM4csFrYtdGJoRLbPY6V8LBbOxgPZIuM0MkPaiOI2F/ASwxMAzoJu9wBw8Pyvx1p27XnrIEKPyDiTqimJ7xbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/plugin-transform-strict-mode": "^7.24.7", + "@babel/preset-env": "^7.25.2", + "@babel/preset-flow": "^7.24.7", + "@babel/preset-react": "^7.24.7", + "@babel/preset-typescript": "^7.24.7", + "babel-plugin-module-resolver": "^5.0.2", + "browserslist": "^4.20.4", + "cosmiconfig": "^9.0.0", + "cross-spawn": "^7.0.3", + "dedent": "^0.7.0", + "del": "^6.1.1", + "escape-string-regexp": "^4.0.0", + "fs-extra": "^10.1.0", + "glob": "^8.0.3", + "is-git-dirty": "^2.0.1", + "json5": "^2.2.1", + "kleur": "^4.1.4", + "metro-config": "^0.80.9", + "prompts": "^2.4.2", + "which": "^2.0.2", + "yargs": "^17.5.1" + }, + "bin": { + "bob": "bin/bob" + }, + "engines": { + "node": ">= 20.0.0" + } + }, + "node_modules/react-native-builder-bob/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/react-native-builder-bob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/react-native-builder-bob/node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/react-native-builder-bob/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/react-native-builder-bob/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/react-native-builder-bob/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/react-native-builder-bob/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/react-native-builder-bob/node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react-native-builder-bob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/react-native/node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/react-native/node_modules/@jest/environment/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/react-native/node_modules/@jest/environment/node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/react-native/node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/react-native/node_modules/@jest/fake-timers/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/react-native/node_modules/@jest/fake-timers/node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/react-native/node_modules/@jest/types": { + "version": "26.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/react-native/node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/react-native/node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/react-native/node_modules/@types/yargs": { + "version": "15.0.14", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/react-native/node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/react-native/node_modules/jest-environment-node/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/react-native/node_modules/jest-environment-node/node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/react-native/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/react-native/node_modules/jest-message-util/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/react-native/node_modules/jest-message-util/node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/react-native/node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/react-native/node_modules/jest-message-util/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/react-native/node_modules/jest-message-util/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-native/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/react-native/node_modules/jest-mock/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/react-native/node_modules/jest-mock/node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/react-native/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/react-native/node_modules/jest-util/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/react-native/node_modules/jest-util/node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/react-native/node_modules/pretty-format": { + "version": "26.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/react-native/node_modules/ws": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", + "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-shallow-renderer": { + "version": "16.15.0", + "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", + "integrity": "sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4.1.1", + "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readline": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz", + "integrity": "sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==", + "dev": true, + "license": "BSD" + }, + "node_modules/recast": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.21.5.tgz", + "integrity": "sha512-hjMmLaUXAm1hIuTqOdeYObMslq/q+Xff6QE3Y2P+uoHAg2nmVlLBps2hzh1UJDdMtDTMXOFewK6ky51JQIeECg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "0.15.2", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexpu-core": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", + "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.12.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.0.2" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true, + "license": "ISC" + }, + "node_modules/reselect": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", + "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.24.0-canary-efb381bbf-20230505", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.24.0-canary-efb381bbf-20230505.tgz", + "integrity": "sha512-ABvovCDe/k9IluqSh4/ISoq8tIJnW8euVAWYt5j/bg6dRnqwQwiGO1F/V4AyK96NGF/FB04FhOUDuWj8IKfABA==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-static/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "license": "ISC" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "dev": true, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "dev": true, + "license": "MIT" + }, + "node_modules/stacktrace-parser": { + "version": "0.1.10", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strnum": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz", + "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/sudo-prompt": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/sudo-prompt/-/sudo-prompt-9.2.1.tgz", + "integrity": "sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/temp": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz", + "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "rimraf": "~2.6.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/temp/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/terser": { + "version": "5.39.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz", + "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/through2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/through2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/to-regex-range/node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-detect": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.7.1", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vlq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", + "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/walker": { + "version": "1.0.8", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/whatwg-fetch": { + "version": "3.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/which": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "2.4.3", + "dev": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/js/react_native/package.json b/js/react_native/package.json index c33c1cdfb6f22..4ac4fa79d49fc 100644 --- a/js/react_native/package.json +++ b/js/react_native/package.json @@ -2,7 +2,7 @@ "react-native": "lib/index", "module": "dist/module/index", "engines": { - "node": ">=16" + "node": ">=18" }, "jest": { "modulePathIgnorePatterns": [ @@ -20,14 +20,13 @@ "ONNX Runtime" ], "devDependencies": { - "@types/jest": "^29.2.1", - "@types/react": "^18.0.24", - "@tsconfig/react-native": "^3.0.0", - "jest": "^29.2.1", + "@react-native/typescript-config": "0.73.1", + "@types/react": "^18.2.6", "pod-install": "^0.1.36", - "prettier": "^2.6.2", + "prettier": "^2.8.8", "react": "^18.2.0", - "react-native": "^0.72.17" + "react-native": "^0.73.11", + "react-native-builder-bob": "^0.37.0" }, "peerDependencies": { "react": "*", @@ -38,7 +37,7 @@ "registry": "https://registry.npmjs.org/" }, "source": "lib/index", - "version": "1.21.0", + "version": "1.22.0", "main": "dist/commonjs/index", "homepage": "https://github.com/microsoft/onnxruntime/blob/main/js/react_native/README.md", "files": [ @@ -62,22 +61,38 @@ ], "description": "ONNX Runtime bridge for react native", "repository": "https://github.com/Microsoft/onnxruntime.git", + "react-native-builder-bob": { + "source": "lib", + "targets": [ + "commonjs", + "module", + [ + "typescript", + { + "project": "tsconfig.build.json", + "tsc": "../node_modules/.bin/tsc" + } + ] + ], + "output": "dist" + }, "dependencies": { - "@expo/config-plugins": "^7.2.4", "buffer": "^6.0.3", "onnxruntime-common": "file:../common" }, "scripts": { "typescript": "tsc --noEmit", - "bootstrap": "yarn pack-common && yarn unpack-common && yarn pack-libs && yarn unpack-libs && yarn e2e && yarn pods", + "prepare": "bob build", + "bootstrap-no-pods": "npm run pack-common && npm run unpack-common && npm run pack-libs && npm run unpack-libs && npm run e2e", + "bootstrap": "npm run bootstrap-no-pods && npm run pods", "test": "jest", "pack-common": "cd ../common && npm pack && mv -f onnxruntime-common-*.tgz ../react_native/e2e/onnxruntime-common.tgz", - "unpack-common": "cd e2e && yarn add --no-lockfile file:./onnxruntime-common.tgz", + "unpack-common": "npm --prefix e2e install ./e2e/onnxruntime-common.tgz", "pack-libs": "npm pack --ort-js-pack-mode=e2e && mv -f onnxruntime-react-native-*.tgz e2e/onnxruntime-react-native.tgz", - "unpack-libs": "cd e2e && yarn add --no-lockfile file:./onnxruntime-react-native.tgz", + "unpack-libs": "npm --prefix e2e install ./e2e/onnxruntime-react-native.tgz", "prepack": "tsc --build ./tsconfig.scripts.json && node ./scripts/prepack", - "pods": "cd e2e && pod-install --quiet", - "e2e": "yarn --cwd e2e" + "pods": "cd e2e && npx pod-install --quiet", + "e2e": "npm --prefix e2e install" }, "types": "dist/typescript/index.d.ts", "name": "onnxruntime-react-native", diff --git a/js/react_native/scripts/bootstrap.js b/js/react_native/scripts/bootstrap.js index 34650de57d4c6..11b00c3c5bee4 100644 --- a/js/react_native/scripts/bootstrap.js +++ b/js/react_native/scripts/bootstrap.js @@ -17,10 +17,7 @@ let result; if (process.cwd() !== root || args.length) { // We're not in the root of the project, or additional arguments were passed // In this case, forward the command to `yarn` - result = child_process.spawnSync('yarn', args, options); -} else { - // If `yarn` is run without arguments, perform bootstrap - result = child_process.spawnSync('yarn', ['bootstrap'], options); + result = child_process.spawnSync('npm', args, options); } process.exitCode = result.status; diff --git a/js/react_native/yarn.lock b/js/react_native/yarn.lock deleted file mode 100644 index 8ee2ddd436938..0000000000000 --- a/js/react_native/yarn.lock +++ /dev/null @@ -1,5523 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@ampproject/remapping@^2.1.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" - integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== - dependencies: - "@jridgewell/gen-mapping" "^0.1.0" - "@jridgewell/trace-mapping" "^0.3.9" - -"@ampproject/remapping@^2.2.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" - integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== - dependencies: - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.24" - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" - integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== - dependencies: - "@babel/highlight" "^7.16.7" - -"@babel/code-frame@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" - integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== - dependencies: - "@babel/highlight" "^7.18.6" - -"@babel/code-frame@^7.22.13": - version "7.22.13" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e" - integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w== - dependencies: - "@babel/highlight" "^7.22.13" - chalk "^2.4.2" - -"@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.2": - version "7.26.2" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" - integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== - dependencies: - "@babel/helper-validator-identifier" "^7.25.9" - js-tokens "^4.0.0" - picocolors "^1.0.0" - -"@babel/code-frame@~7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" - integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== - dependencies: - "@babel/highlight" "^7.10.4" - -"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.17.10": - version "7.17.10" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.10.tgz#711dc726a492dfc8be8220028b1b92482362baab" - integrity sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw== - -"@babel/compat-data@^7.20.5", "@babel/compat-data@^7.26.5": - version "7.26.5" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.5.tgz#df93ac37f4417854130e21d72c66ff3d4b897fc7" - integrity sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg== - -"@babel/core@^7.11.6", "@babel/core@^7.20.0", "@babel/core@^7.23.9": - version "7.26.7" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.7.tgz#0439347a183b97534d52811144d763a17f9d2b24" - integrity sha512-SRijHmF0PSPgLIBYlWnG0hyeJLwXE2CgpsXaMOrtt2yp9/86ALw6oUlj9KYuZ0JN07T4eBMVIW4li/9S1j2BGA== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.26.2" - "@babel/generator" "^7.26.5" - "@babel/helper-compilation-targets" "^7.26.5" - "@babel/helper-module-transforms" "^7.26.0" - "@babel/helpers" "^7.26.7" - "@babel/parser" "^7.26.7" - "@babel/template" "^7.25.9" - "@babel/traverse" "^7.26.7" - "@babel/types" "^7.26.7" - convert-source-map "^2.0.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.3" - semver "^6.3.1" - -"@babel/core@^7.12.3", "@babel/core@^7.13.16": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.2.tgz#87b2fcd7cce9becaa7f5acebdc4f09f3dd19d876" - integrity sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ== - dependencies: - "@ampproject/remapping" "^2.1.0" - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.18.2" - "@babel/helper-compilation-targets" "^7.18.2" - "@babel/helper-module-transforms" "^7.18.0" - "@babel/helpers" "^7.18.2" - "@babel/parser" "^7.18.0" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.18.2" - "@babel/types" "^7.18.2" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.1" - semver "^6.3.0" - -"@babel/generator@^7.18.2", "@babel/generator@^7.7.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.2.tgz#33873d6f89b21efe2da63fe554460f3df1c5880d" - integrity sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw== - dependencies: - "@babel/types" "^7.18.2" - "@jridgewell/gen-mapping" "^0.3.0" - jsesc "^2.5.1" - -"@babel/generator@^7.20.0", "@babel/generator@^7.26.5": - version "7.26.5" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.5.tgz#e44d4ab3176bbcaf78a5725da5f1dc28802a9458" - integrity sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw== - dependencies: - "@babel/parser" "^7.26.5" - "@babel/types" "^7.26.5" - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" - jsesc "^3.0.2" - -"@babel/generator@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420" - integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g== - dependencies: - "@babel/types" "^7.23.0" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" - jsesc "^2.5.1" - -"@babel/helper-annotate-as-pure@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862" - integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-annotate-as-pure@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" - integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA== - dependencies: - "@babel/types" "^7.18.6" - -"@babel/helper-annotate-as-pure@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz#d8eac4d2dc0d7b6e11fa6e535332e0d3184f06b4" - integrity sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g== - dependencies: - "@babel/types" "^7.25.9" - -"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.7", "@babel/helper-compilation-targets@^7.17.10", "@babel/helper-compilation-targets@^7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz#67a85a10cbd5fc7f1457fec2e7f45441dc6c754b" - integrity sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ== - dependencies: - "@babel/compat-data" "^7.17.10" - "@babel/helper-validator-option" "^7.16.7" - browserslist "^4.20.2" - semver "^6.3.0" - -"@babel/helper-compilation-targets@^7.20.7", "@babel/helper-compilation-targets@^7.26.5": - version "7.26.5" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz#75d92bb8d8d51301c0d49e52a65c9a7fe94514d8" - integrity sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA== - dependencies: - "@babel/compat-data" "^7.26.5" - "@babel/helper-validator-option" "^7.25.9" - browserslist "^4.24.0" - lru-cache "^5.1.1" - semver "^6.3.1" - -"@babel/helper-create-class-features-plugin@^7.17.12", "@babel/helper-create-class-features-plugin@^7.18.0": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.0.tgz#fac430912606331cb075ea8d82f9a4c145a4da19" - integrity sha512-Kh8zTGR9de3J63e5nS0rQUdRs/kbtwoeQQ0sriS0lItjC96u8XXZN6lKpuyWd2coKSU13py/y+LTmThLuVX0Pg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.17.9" - "@babel/helper-member-expression-to-functions" "^7.17.7" - "@babel/helper-optimise-call-expression" "^7.16.7" - "@babel/helper-replace-supers" "^7.16.7" - "@babel/helper-split-export-declaration" "^7.16.7" - -"@babel/helper-create-class-features-plugin@^7.18.6": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz#7644147706bb90ff613297d49ed5266bde729f83" - integrity sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.25.9" - "@babel/helper-member-expression-to-functions" "^7.25.9" - "@babel/helper-optimise-call-expression" "^7.25.9" - "@babel/helper-replace-supers" "^7.25.9" - "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" - "@babel/traverse" "^7.25.9" - semver "^6.3.1" - -"@babel/helper-create-regexp-features-plugin@^7.16.7": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.12.tgz#bb37ca467f9694bbe55b884ae7a5cc1e0084e4fd" - integrity sha512-b2aZrV4zvutr9AIa6/gA3wsZKRwTKYoDxYiFKcESS3Ug2GTXzwBEvMuuFLhCQpEnRXs1zng4ISAXSUxxKBIcxw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - regexpu-core "^5.0.1" - -"@babel/helper-create-regexp-features-plugin@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.18.6.tgz#3e35f4e04acbbf25f1b3534a657610a000543d3c" - integrity sha512-7LcpH1wnQLGrI+4v+nPp+zUvIkF9x0ddv1Hkdue10tg3gmRnLy97DXh4STiOf1qeIInyD69Qv5kKSZzKD8B/7A== - dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - regexpu-core "^5.1.0" - -"@babel/helper-define-polyfill-provider@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz#52411b445bdb2e676869e5a74960d2d3826d2665" - integrity sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA== - dependencies: - "@babel/helper-compilation-targets" "^7.13.0" - "@babel/helper-module-imports" "^7.12.13" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/traverse" "^7.13.0" - debug "^4.1.1" - lodash.debounce "^4.0.8" - resolve "^1.14.2" - semver "^6.1.2" - -"@babel/helper-environment-visitor@^7.16.7", "@babel/helper-environment-visitor@^7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz#8a6d2dedb53f6bf248e31b4baf38739ee4a637bd" - integrity sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ== - -"@babel/helper-environment-visitor@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.6.tgz#b7eee2b5b9d70602e59d1a6cad7dd24de7ca6cd7" - integrity sha512-8n6gSfn2baOY+qlp+VSzsosjCVGFqWKmDF0cCWOybh52Dw3SEyoWR1KrhMJASjLwIEkkAufZ0xvr+SxLHSpy2Q== - -"@babel/helper-environment-visitor@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" - integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== - -"@babel/helper-function-name@^7.16.7", "@babel/helper-function-name@^7.17.9": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz#136fcd54bc1da82fcb47565cf16fd8e444b1ff12" - integrity sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg== - dependencies: - "@babel/template" "^7.16.7" - "@babel/types" "^7.17.0" - -"@babel/helper-function-name@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.18.6.tgz#8334fecb0afba66e6d87a7e8c6bb7fed79926b83" - integrity sha512-0mWMxV1aC97dhjCah5U5Ua7668r5ZmSC2DLfH2EZnf9c3/dHZKiFa5pRLMH5tjSl471tY6496ZWk/kjNONBxhw== - dependencies: - "@babel/template" "^7.18.6" - "@babel/types" "^7.18.6" - -"@babel/helper-function-name@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" - integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== - dependencies: - "@babel/template" "^7.22.15" - "@babel/types" "^7.23.0" - -"@babel/helper-hoist-variables@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" - integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-member-expression-to-functions@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz#a34013b57d8542a8c4ff8ba3f747c02452a4d8c4" - integrity sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw== - dependencies: - "@babel/types" "^7.17.0" - -"@babel/helper-member-expression-to-functions@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz#9dfffe46f727005a5ea29051ac835fb735e4c1a3" - integrity sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ== - dependencies: - "@babel/traverse" "^7.25.9" - "@babel/types" "^7.25.9" - -"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" - integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-module-imports@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz#e7f8d20602ebdbf9ebbea0a0751fb0f2a4141715" - integrity sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw== - dependencies: - "@babel/traverse" "^7.25.9" - "@babel/types" "^7.25.9" - -"@babel/helper-module-transforms@^7.18.0": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz#baf05dec7a5875fb9235bd34ca18bad4e21221cd" - integrity sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA== - dependencies: - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-simple-access" "^7.17.7" - "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/helper-validator-identifier" "^7.16.7" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.18.0" - "@babel/types" "^7.18.0" - -"@babel/helper-module-transforms@^7.26.0": - version "7.26.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz#8ce54ec9d592695e58d84cd884b7b5c6a2fdeeae" - integrity sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw== - dependencies: - "@babel/helper-module-imports" "^7.25.9" - "@babel/helper-validator-identifier" "^7.25.9" - "@babel/traverse" "^7.25.9" - -"@babel/helper-optimise-call-expression@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz#a34e3560605abbd31a18546bd2aad3e6d9a174f2" - integrity sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-optimise-call-expression@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz#3324ae50bae7e2ab3c33f60c9a877b6a0146b54e" - integrity sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ== - dependencies: - "@babel/types" "^7.25.9" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.17.12", "@babel/helper-plugin-utils@^7.8.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz#86c2347da5acbf5583ba0a10aed4c9bf9da9cf96" - integrity sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA== - -"@babel/helper-plugin-utils@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz#9448974dd4fb1d80fefe72e8a0af37809cd30d6d" - integrity sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg== - -"@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.25.9", "@babel/helper-plugin-utils@^7.26.5": - version "7.26.5" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz#18580d00c9934117ad719392c4f6585c9333cc35" - integrity sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg== - -"@babel/helper-remap-async-to-generator@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.6.tgz#fa1f81acd19daee9d73de297c0308783cd3cfc23" - integrity sha512-z5wbmV55TveUPZlCLZvxWHtrjuJd+8inFhk7DG0WW87/oJuGDcjDiu7HIvGcpf5464L6xKCg3vNkmlVVz9hwyQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-environment-visitor" "^7.18.6" - "@babel/helper-wrap-function" "^7.18.6" - "@babel/types" "^7.18.6" - -"@babel/helper-remap-async-to-generator@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz#e53956ab3d5b9fb88be04b3e2f31b523afd34b92" - integrity sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.25.9" - "@babel/helper-wrap-function" "^7.25.9" - "@babel/traverse" "^7.25.9" - -"@babel/helper-replace-supers@^7.16.7": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.18.2.tgz#41fdfcc9abaf900e18ba6e5931816d9062a7b2e0" - integrity sha512-XzAIyxx+vFnrOxiQrToSUOzUOn0e1J2Li40ntddek1Y69AXUTXoDJ40/D5RdjFu7s7qHiaeoTiempZcbuVXh2Q== - dependencies: - "@babel/helper-environment-visitor" "^7.18.2" - "@babel/helper-member-expression-to-functions" "^7.17.7" - "@babel/helper-optimise-call-expression" "^7.16.7" - "@babel/traverse" "^7.18.2" - "@babel/types" "^7.18.2" - -"@babel/helper-replace-supers@^7.25.9": - version "7.26.5" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz#6cb04e82ae291dae8e72335dfe438b0725f14c8d" - integrity sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.25.9" - "@babel/helper-optimise-call-expression" "^7.25.9" - "@babel/traverse" "^7.26.5" - -"@babel/helper-simple-access@^7.17.7", "@babel/helper-simple-access@^7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz#4dc473c2169ac3a1c9f4a51cfcd091d1c36fcff9" - integrity sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ== - dependencies: - "@babel/types" "^7.18.2" - -"@babel/helper-skip-transparent-expression-wrappers@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz#0ee3388070147c3ae051e487eca3ebb0e2e8bb09" - integrity sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw== - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-skip-transparent-expression-wrappers@^7.20.0", "@babel/helper-skip-transparent-expression-wrappers@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz#0b2e1b62d560d6b1954893fd2b705dc17c91f0c9" - integrity sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA== - dependencies: - "@babel/traverse" "^7.25.9" - "@babel/types" "^7.25.9" - -"@babel/helper-split-export-declaration@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" - integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-split-export-declaration@^7.22.6": - version "7.22.6" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" - integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-string-parser@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" - integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== - -"@babel/helper-string-parser@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c" - integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== - -"@babel/helper-validator-identifier@^7.16.7": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" - integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== - -"@babel/helper-validator-identifier@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076" - integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g== - -"@babel/helper-validator-identifier@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" - integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== - -"@babel/helper-validator-identifier@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" - integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== - -"@babel/helper-validator-option@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" - integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== - -"@babel/helper-validator-option@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72" - integrity sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw== - -"@babel/helper-wrap-function@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.18.6.tgz#ec44ea4ad9d8988b90c3e465ba2382f4de81a073" - integrity sha512-I5/LZfozwMNbwr/b1vhhuYD+J/mU+gfGAj5td7l5Rv9WYmH6i3Om69WGKNmlIpsVW/mF6O5bvTKbvDQZVgjqOw== - dependencies: - "@babel/helper-function-name" "^7.18.6" - "@babel/template" "^7.18.6" - "@babel/traverse" "^7.18.6" - "@babel/types" "^7.18.6" - -"@babel/helper-wrap-function@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz#d99dfd595312e6c894bd7d237470025c85eea9d0" - integrity sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g== - dependencies: - "@babel/template" "^7.25.9" - "@babel/traverse" "^7.25.9" - "@babel/types" "^7.25.9" - -"@babel/helpers@^7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.2.tgz#970d74f0deadc3f5a938bfa250738eb4ac889384" - integrity sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg== - dependencies: - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.18.2" - "@babel/types" "^7.18.2" - -"@babel/helpers@^7.26.7": - version "7.26.7" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.26.7.tgz#fd1d2a7c431b6e39290277aacfd8367857c576a4" - integrity sha512-8NHiL98vsi0mbPQmYAGWwfcFaOy4j2HY49fXJCfuDcdE7fMIsH9a7GdaeXpIBsbT7307WU8KCMp5pUVDNL4f9A== - dependencies: - "@babel/template" "^7.25.9" - "@babel/types" "^7.26.7" - -"@babel/highlight@^7.10.4", "@babel/highlight@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" - integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== - dependencies: - "@babel/helper-validator-identifier" "^7.18.6" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/highlight@^7.16.7": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.17.12.tgz#257de56ee5afbd20451ac0a75686b6b404257351" - integrity sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg== - dependencies: - "@babel/helper-validator-identifier" "^7.16.7" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/highlight@^7.22.13": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54" - integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg== - dependencies: - "@babel/helper-validator-identifier" "^7.22.20" - chalk "^2.4.2" - js-tokens "^4.0.0" - -"@babel/parser@^7.1.0", "@babel/parser@^7.13.16", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.18.0": - version "7.18.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.3.tgz#39e99c7b0c4c56cef4d1eed8de9f506411c2ebc2" - integrity sha512-rL50YcEuHbbauAFAysNsJA4/f89fGTOBRNs9P81sniKnKAr4xULe5AecolcsKbi88xu0ByWYDj/S1AJ3FSFuSQ== - -"@babel/parser@^7.18.6": - version "7.18.8" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.8.tgz#822146080ac9c62dac0823bb3489622e0bc1cbdf" - integrity sha512-RSKRfYX20dyH+elbJK2uqAkVyucL+xXzhqlMD5/ZXx+dAAwpyB7HsvnHe/ZUGOF+xLr5Wx9/JoXVTj6BQE2/oA== - -"@babel/parser@^7.20.0", "@babel/parser@^7.23.9", "@babel/parser@^7.25.9", "@babel/parser@^7.26.5", "@babel/parser@^7.26.7": - version "7.26.7" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.7.tgz#e114cd099e5f7d17b05368678da0fb9f69b3385c" - integrity sha512-kEvgGGgEjRUutvdVvZhbn/BxVt+5VSpwXz1j3WYXQbXDo8KzFOPNG2GQbdAiNq8g6wn1yKk7C/qrke03a84V+w== - dependencies: - "@babel/types" "^7.26.7" - -"@babel/parser@^7.22.15", "@babel/parser@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719" - integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw== - -"@babel/plugin-proposal-async-generator-functions@^7.0.0": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.6.tgz#aedac81e6fc12bb643374656dd5f2605bf743d17" - integrity sha512-WAz4R9bvozx4qwf74M+sfqPMKfSqwM0phxPTR6iJIi8robgzXwkEgmeJG1gEKhm6sDqT/U9aV3lfcqybIpev8w== - dependencies: - "@babel/helper-environment-visitor" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/helper-remap-async-to-generator" "^7.18.6" - "@babel/plugin-syntax-async-generators" "^7.8.4" - -"@babel/plugin-proposal-class-properties@^7.0.0", "@babel/plugin-proposal-class-properties@^7.13.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.17.12.tgz#84f65c0cc247d46f40a6da99aadd6438315d80a4" - integrity sha512-U0mI9q8pW5Q9EaTHFPwSVusPMV/DV9Mm8p7csqROFLtIE9rBF5piLqyrBGigftALrBcsBGu4m38JneAe7ZDLXw== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.17.12" - "@babel/helper-plugin-utils" "^7.17.12" - -"@babel/plugin-proposal-class-properties@^7.18.0": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" - integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-proposal-export-default-from@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.17.12.tgz#df785e638618d8ffa14e08c78c44d9695d083b73" - integrity sha512-LpsTRw725eBAXXKUOnJJct+SEaOzwR78zahcLuripD2+dKc2Sj+8Q2DzA+GC/jOpOu/KlDXuxrzG214o1zTauQ== - dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/plugin-syntax-export-default-from" "^7.16.7" - -"@babel/plugin-proposal-nullish-coalescing-operator@^7.13.8": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.17.12.tgz#1e93079bbc2cbc756f6db6a1925157c4a92b94be" - integrity sha512-ws/g3FSGVzv+VH86+QvgtuJL/kR67xaEIF2x0iPqdDfYW6ra6JF3lKVBkWynRLcNtIC1oCTfDRVxmm2mKzy+ag== - dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - -"@babel/plugin-proposal-nullish-coalescing-operator@^7.18.0": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz#fdd940a99a740e577d6c753ab6fbb43fdb9467e1" - integrity sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - -"@babel/plugin-proposal-numeric-separator@^7.0.0": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz#899b14fbafe87f053d2c5ff05b36029c62e13c75" - integrity sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - -"@babel/plugin-proposal-object-rest-spread@^7.0.0": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.0.tgz#79f2390c892ba2a68ec112eb0d895cfbd11155e8" - integrity sha512-nbTv371eTrFabDfHLElkn9oyf9VG+VKK6WMzhY2o4eHKaG19BToD9947zzGMO6I/Irstx9d8CwX6njPNIAR/yw== - dependencies: - "@babel/compat-data" "^7.17.10" - "@babel/helper-compilation-targets" "^7.17.10" - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.17.12" - -"@babel/plugin-proposal-object-rest-spread@^7.20.0": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz#aa662940ef425779c75534a5c41e9d936edc390a" - integrity sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg== - dependencies: - "@babel/compat-data" "^7.20.5" - "@babel/helper-compilation-targets" "^7.20.7" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.20.7" - -"@babel/plugin-proposal-optional-catch-binding@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz#c623a430674ffc4ab732fd0a0ae7722b67cb74cf" - integrity sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - -"@babel/plugin-proposal-optional-chaining@^7.13.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.17.12.tgz#f96949e9bacace3a9066323a5cf90cfb9de67174" - integrity sha512-7wigcOs/Z4YWlK7xxjkvaIw84vGhDv/P1dFGQap0nHkc8gFKY/r+hXc8Qzf5k1gY7CvGIcHqAnOagVKJJ1wVOQ== - dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - -"@babel/plugin-proposal-optional-chaining@^7.20.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz#886f5c8978deb7d30f678b2e24346b287234d3ea" - integrity sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - -"@babel/plugin-syntax-async-generators@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" - integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-bigint@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" - integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-class-properties@^7.0.0", "@babel/plugin-syntax-class-properties@^7.8.3": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" - integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - -"@babel/plugin-syntax-dynamic-import@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" - integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-export-default-from@^7.0.0", "@babel/plugin-syntax-export-default-from@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.16.7.tgz#fa89cf13b60de2c3f79acdc2b52a21174c6de060" - integrity sha512-4C3E4NsrLOgftKaTYTULhHsuQrGv3FHrBzOMDiS7UYKIpgGBkAdawg4h+EI8zPeK9M0fiIIh72hIwsI24K7MbA== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - -"@babel/plugin-syntax-flow@^7.0.0", "@babel/plugin-syntax-flow@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.17.12.tgz#23d852902acd19f42923fca9d0f196984d124e73" - integrity sha512-B8QIgBvkIG6G2jgsOHQUist7Sm0EBLDCx8sen072IwqNuzMegZNXrYnSv77cYzA8mLDZAfQYqsLIhimiP1s2HQ== - dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - -"@babel/plugin-syntax-flow@^7.12.1", "@babel/plugin-syntax-flow@^7.18.0", "@babel/plugin-syntax-flow@^7.26.0": - version "7.26.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.26.0.tgz#96507595c21b45fccfc2bc758d5c45452e6164fa" - integrity sha512-B+O2DnPc0iG+YXFqOxv2WNuNU97ToWjOomUQ78DouOENWUaM5sVrmet9mcomUGQFwpJd//gvUagXBSdzO1fRKg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-syntax-import-meta@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" - integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-json-strings@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" - integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-jsx@^7.0.0", "@babel/plugin-syntax-jsx@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.17.12.tgz#834035b45061983a491f60096f61a2e7c5674a47" - integrity sha512-spyY3E3AURfxh/RHtjx5j6hs8am5NbUBGfcZ2vB3uShSpZdQyXSf5rR5Mk76vbtlAZOelyVQ71Fg0x9SG4fsog== - dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - -"@babel/plugin-syntax-jsx@^7.7.2": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz#a34313a178ea56f1951599b929c1ceacee719290" - integrity sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" - integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-nullish-coalescing-operator@^7.0.0", "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" - integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" - integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" - integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-catch-binding@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" - integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-chaining@^7.0.0", "@babel/plugin-syntax-optional-chaining@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" - integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-top-level-await@^7.8.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" - integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-typescript@^7.17.12", "@babel/plugin-syntax-typescript@^7.7.2": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.17.12.tgz#b54fc3be6de734a56b87508f99d6428b5b605a7b" - integrity sha512-TYY0SXFiO31YXtNg3HtFwNJHjLsAyIIhAhNWkQ5whPPS7HWUFlg9z0Ta4qAQNjQbP1wsSt/oKkmZ/4/WWdMUpw== - dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - -"@babel/plugin-transform-arrow-functions@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.17.12.tgz#dddd783b473b1b1537ef46423e3944ff24898c45" - integrity sha512-PHln3CNi/49V+mza4xMwrg+WGYevSF1oaiXaC2EQfdp4HWlSjRsrDXWJiQBKpP7749u6vQ9mcry2uuFOv5CXvA== - dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - -"@babel/plugin-transform-async-to-generator@^7.20.0": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz#c80008dacae51482793e5a9c08b39a5be7e12d71" - integrity sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ== - dependencies: - "@babel/helper-module-imports" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-remap-async-to-generator" "^7.25.9" - -"@babel/plugin-transform-block-scoped-functions@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz#4d0d57d9632ef6062cdf354bb717102ee042a620" - integrity sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - -"@babel/plugin-transform-block-scoping@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.17.12.tgz#68fc3c4b3bb7dfd809d97b7ed19a584052a2725c" - integrity sha512-jw8XW/B1i7Lqwqj2CbrViPcZijSxfguBWZP2aN59NHgxUyO/OcO1mfdCxH13QhN5LbWhPkX+f+brKGhZTiqtZQ== - dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - -"@babel/plugin-transform-classes@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.17.12.tgz#da889e89a4d38375eeb24985218edeab93af4f29" - integrity sha512-cvO7lc7pZat6BsvH6l/EGaI8zpl8paICaoGk+7x7guvtfak/TbIf66nYmJOH13EuG0H+Xx3M+9LQDtSvZFKXKw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.17.9" - "@babel/helper-optimise-call-expression" "^7.16.7" - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-replace-supers" "^7.16.7" - "@babel/helper-split-export-declaration" "^7.16.7" - globals "^11.1.0" - -"@babel/plugin-transform-computed-properties@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.17.12.tgz#bca616a83679698f3258e892ed422546e531387f" - integrity sha512-a7XINeplB5cQUWMg1E/GI1tFz3LfK021IjV1rj1ypE+R7jHm+pIHmHl25VNkZxtx9uuYp7ThGk8fur1HHG7PgQ== - dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - -"@babel/plugin-transform-destructuring@^7.0.0": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.0.tgz#dc4f92587e291b4daa78aa20cc2d7a63aa11e858" - integrity sha512-Mo69klS79z6KEfrLg/1WkmVnB8javh75HX4pi2btjvlIoasuxilEyjtsQW6XPrubNd7AQy0MMaNIaQE4e7+PQw== - dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - -"@babel/plugin-transform-destructuring@^7.20.0": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz#966ea2595c498224340883602d3cfd7a0c79cea1" - integrity sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-flow-strip-types@^7.0.0", "@babel/plugin-transform-flow-strip-types@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.17.12.tgz#5e070f99a4152194bd9275de140e83a92966cab3" - integrity sha512-g8cSNt+cHCpG/uunPQELdq/TeV3eg1OLJYwxypwHtAWo9+nErH3lQx9CSO2uI9lF74A0mR0t4KoMjs1snSgnTw== - dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/plugin-syntax-flow" "^7.17.12" - -"@babel/plugin-transform-flow-strip-types@^7.20.0": - version "7.26.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.26.5.tgz#2904c85a814e7abb1f4850b8baf4f07d0a2389d4" - integrity sha512-eGK26RsbIkYUns3Y8qKl362juDDYK+wEdPGHGrhzUl6CewZFo55VZ7hg+CyMFU4dd5QQakBN86nBMpRsFpRvbQ== - dependencies: - "@babel/helper-plugin-utils" "^7.26.5" - "@babel/plugin-syntax-flow" "^7.26.0" - -"@babel/plugin-transform-for-of@^7.0.0": - version "7.18.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.1.tgz#ed14b657e162b72afbbb2b4cdad277bf2bb32036" - integrity sha512-+TTB5XwvJ5hZbO8xvl2H4XaMDOAK57zF4miuC9qQJgysPNEAZZ9Z69rdF5LJkozGdZrjBIUAIyKUWRMmebI7vg== - dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - -"@babel/plugin-transform-function-name@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz#5ab34375c64d61d083d7d2f05c38d90b97ec65cf" - integrity sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA== - dependencies: - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-function-name" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - -"@babel/plugin-transform-literals@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.17.12.tgz#97131fbc6bbb261487105b4b3edbf9ebf9c830ae" - integrity sha512-8iRkvaTjJciWycPIZ9k9duu663FT7VrBdNqNgxnVXEFwOIp55JWcZd23VBRySYbnS3PwQ3rGiabJBBBGj5APmQ== - dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - -"@babel/plugin-transform-member-expression-literals@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz#6e5dcf906ef8a098e630149d14c867dd28f92384" - integrity sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - -"@babel/plugin-transform-modules-commonjs@^7.0.0", "@babel/plugin-transform-modules-commonjs@^7.13.8": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.2.tgz#1aa8efa2e2a6e818b6a7f2235fceaf09bdb31e9e" - integrity sha512-f5A865gFPAJAEE0K7F/+nm5CmAE3y8AWlMBG9unu5j9+tk50UQVK0QS8RNxSp7MJf0wh97uYyLWt3Zvu71zyOQ== - dependencies: - "@babel/helper-module-transforms" "^7.18.0" - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-simple-access" "^7.18.2" - babel-plugin-dynamic-import-node "^2.3.3" - -"@babel/plugin-transform-named-capturing-groups-regex@^7.0.0": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.18.6.tgz#c89bfbc7cc6805d692f3a49bc5fc1b630007246d" - integrity sha512-UmEOGF8XgaIqD74bC8g7iV3RYj8lMf0Bw7NJzvnS9qQhM4mg+1WHKotUIdjxgD2RGrgFLZZPCFPFj3P/kVDYhg== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-object-super@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz#ac359cf8d32cf4354d27a46867999490b6c32a94" - integrity sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-replace-supers" "^7.16.7" - -"@babel/plugin-transform-parameters@^7.0.0", "@babel/plugin-transform-parameters@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.17.12.tgz#eb467cd9586ff5ff115a9880d6fdbd4a846b7766" - integrity sha512-6qW4rWo1cyCdq1FkYri7AHpauchbGLXpdwnYsfxFb+KtddHENfsY5JZb35xUwkK5opOLcJ3BNd2l7PhRYGlwIA== - dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - -"@babel/plugin-transform-parameters@^7.20.7": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz#b856842205b3e77e18b7a7a1b94958069c7ba257" - integrity sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-property-literals@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz#2dadac85155436f22c696c4827730e0fe1057a55" - integrity sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - -"@babel/plugin-transform-react-display-name@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz#7b6d40d232f4c0f550ea348593db3b21e2404340" - integrity sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - -"@babel/plugin-transform-react-jsx-self@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.17.12.tgz#7f2e9b8c08d6a4204733138d8c29d4dba4bb66c2" - integrity sha512-7S9G2B44EnYOx74mue02t1uD8ckWZ/ee6Uz/qfdzc35uWHX5NgRy9i+iJSb2LFRgMd+QV9zNcStQaazzzZ3n3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - -"@babel/plugin-transform-react-jsx-source@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.16.7.tgz#1879c3f23629d287cc6186a6c683154509ec70c0" - integrity sha512-rONFiQz9vgbsnaMtQlZCjIRwhJvlrPET8TabIUK2hzlXw9B9s2Ieaxte1SCOOXMbWRHodbKixNf3BLcWVOQ8Bw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - -"@babel/plugin-transform-react-jsx@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.17.12.tgz#2aa20022709cd6a3f40b45d60603d5f269586dba" - integrity sha512-Lcaw8bxd1DKht3thfD4A12dqo1X16he1Lm8rIv8sTwjAYNInRS1qHa9aJoqvzpscItXvftKDCfaEQzwoVyXpEQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/plugin-syntax-jsx" "^7.17.12" - "@babel/types" "^7.17.12" - -"@babel/plugin-transform-runtime@^7.0.0": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.2.tgz#04637de1e45ae8847ff14b9beead09c33d34374d" - integrity sha512-mr1ufuRMfS52ttq+1G1PD8OJNqgcTFjq3hwn8SZ5n1x1pBhi0E36rYMdTK0TsKtApJ4lDEdfXJwtGobQMHSMPg== - dependencies: - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-plugin-utils" "^7.17.12" - babel-plugin-polyfill-corejs2 "^0.3.0" - babel-plugin-polyfill-corejs3 "^0.5.0" - babel-plugin-polyfill-regenerator "^0.3.0" - semver "^6.3.0" - -"@babel/plugin-transform-shorthand-properties@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz#e8549ae4afcf8382f711794c0c7b6b934c5fbd2a" - integrity sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - -"@babel/plugin-transform-spread@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.17.12.tgz#c112cad3064299f03ea32afed1d659223935d1f5" - integrity sha512-9pgmuQAtFi3lpNUstvG9nGfk9DkrdmWNp9KeKPFmuZCpEnxRzYlS8JgwPjYj+1AWDOSvoGN0H30p1cBOmT/Svg== - dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" - -"@babel/plugin-transform-sticky-regex@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz#c84741d4f4a38072b9a1e2e3fd56d359552e8660" - integrity sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - -"@babel/plugin-transform-template-literals@^7.0.0": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.2.tgz#31ed6915721864847c48b656281d0098ea1add28" - integrity sha512-/cmuBVw9sZBGZVOMkpAEaVLwm4JmK2GZ1dFKOGGpMzEHWFmyZZ59lUU0PdRr8YNYeQdNzTDwuxP2X2gzydTc9g== - dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - -"@babel/plugin-transform-typescript@^7.17.12", "@babel/plugin-transform-typescript@^7.5.0": - version "7.18.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.18.1.tgz#5fd8b86130bad95c4a24377b41ab989a9ccad22d" - integrity sha512-F+RJmL479HJmC0KeqqwEGZMg1P7kWArLGbAKfEi9yPthJyMNjF+DjxFF/halfQvq1Q9GFM4TUbYDNV8xe4Ctqg== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.18.0" - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/plugin-syntax-typescript" "^7.17.12" - -"@babel/plugin-transform-unicode-regex@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz#0f7aa4a501198976e25e82702574c34cfebe9ef2" - integrity sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - -"@babel/preset-flow@^7.13.13": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.17.12.tgz#664a5df59190260939eee862800a255bef3bd66f" - integrity sha512-7QDz7k4uiaBdu7N89VKjUn807pJRXmdirQu0KyR9LXnQrr5Jt41eIMKTS7ljej+H29erwmMrwq9Io9mJHLI3Lw== - dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-validator-option" "^7.16.7" - "@babel/plugin-transform-flow-strip-types" "^7.17.12" - -"@babel/preset-typescript@^7.13.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.17.12.tgz#40269e0a0084d56fc5731b6c40febe1c9a4a3e8c" - integrity sha512-S1ViF8W2QwAKUGJXxP9NAfNaqGDdEBJKpYkxHf5Yy2C4NPPzXGeR3Lhk7G8xJaaLcFTRfNjVbtbVtm8Gb0mqvg== - dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-validator-option" "^7.16.7" - "@babel/plugin-transform-typescript" "^7.17.12" - -"@babel/register@^7.13.16": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.17.7.tgz#5eef3e0f4afc07e25e847720e7b987ae33f08d0b" - integrity sha512-fg56SwvXRifootQEDQAu1mKdjh5uthPzdO0N6t358FktfL4XjAVXuH58ULoiW8mesxiOgNIrxiImqEwv0+hRRA== - dependencies: - clone-deep "^4.0.1" - find-cache-dir "^2.0.0" - make-dir "^2.1.0" - pirates "^4.0.5" - source-map-support "^0.5.16" - -"@babel/runtime@^7.0.0": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.6.tgz#6a1ef59f838debd670421f8c7f2cbb8da9751580" - integrity sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/template@^7.0.0", "@babel/template@^7.16.7", "@babel/template@^7.3.3": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" - integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== - dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/parser" "^7.16.7" - "@babel/types" "^7.16.7" - -"@babel/template@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.6.tgz#1283f4993e00b929d6e2d3c72fdc9168a2977a31" - integrity sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw== - dependencies: - "@babel/code-frame" "^7.18.6" - "@babel/parser" "^7.18.6" - "@babel/types" "^7.18.6" - -"@babel/template@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" - integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== - dependencies: - "@babel/code-frame" "^7.22.13" - "@babel/parser" "^7.22.15" - "@babel/types" "^7.22.15" - -"@babel/template@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.9.tgz#ecb62d81a8a6f5dc5fe8abfc3901fc52ddf15016" - integrity sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg== - dependencies: - "@babel/code-frame" "^7.25.9" - "@babel/parser" "^7.25.9" - "@babel/types" "^7.25.9" - -"@babel/traverse@^7.13.0", "@babel/traverse@^7.18.0", "@babel/traverse@^7.18.2", "@babel/traverse@^7.18.6": - version "7.23.2" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8" - integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw== - dependencies: - "@babel/code-frame" "^7.22.13" - "@babel/generator" "^7.23.0" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.23.0" - "@babel/types" "^7.23.0" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/traverse@^7.20.0", "@babel/traverse@^7.25.9", "@babel/traverse@^7.26.5", "@babel/traverse@^7.26.7": - version "7.26.7" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.7.tgz#99a0a136f6a75e7fb8b0a1ace421e0b25994b8bb" - integrity sha512-1x1sgeyRLC3r5fQOM0/xtQKsYjyxmFjaOrLJNtZ81inNjyJHGIolTULPiSc/2qe1/qfpFLisLQYFnnZl7QoedA== - dependencies: - "@babel/code-frame" "^7.26.2" - "@babel/generator" "^7.26.5" - "@babel/parser" "^7.26.7" - "@babel/template" "^7.25.9" - "@babel/types" "^7.26.7" - debug "^4.3.1" - globals "^11.1.0" - -"@babel/types@^7.0.0", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.17.0", "@babel/types@^7.17.12", "@babel/types@^7.18.0", "@babel/types@^7.18.2", "@babel/types@^7.3.0", "@babel/types@^7.3.3": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.2.tgz#191abfed79ebe6f4242f643a9a5cbaa36b10b091" - integrity sha512-0On6B8A4/+mFUto5WERt3EEuG1NznDirvwca1O8UwXQHVY8g3R7OzYgxXdOfMwLO08UrpUD/2+3Bclyq+/C94Q== - dependencies: - "@babel/helper-validator-identifier" "^7.16.7" - to-fast-properties "^2.0.0" - -"@babel/types@^7.18.6": - version "7.18.8" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.8.tgz#c5af199951bf41ba4a6a9a6d0d8ad722b30cd42f" - integrity sha512-qwpdsmraq0aJ3osLJRApsc2ouSJCdnMeZwB0DhbtHAtRpZNZCdlbRnHIgcRKzdE1g0iOGg644fzjOBcdOz9cPw== - dependencies: - "@babel/helper-validator-identifier" "^7.18.6" - to-fast-properties "^2.0.0" - -"@babel/types@^7.20.0", "@babel/types@^7.25.9", "@babel/types@^7.26.5", "@babel/types@^7.26.7": - version "7.26.7" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.7.tgz#5e2b89c0768e874d4d061961f3a5a153d71dc17a" - integrity sha512-t8kDRGrKXyp6+tjUh7hw2RLyclsW4TRoRvRHtSyAX9Bb5ldlFh+90YAYY6awRXrlB4G5G2izNeGySpATlFzmOg== - dependencies: - "@babel/helper-string-parser" "^7.25.9" - "@babel/helper-validator-identifier" "^7.25.9" - -"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb" - integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg== - dependencies: - "@babel/helper-string-parser" "^7.22.5" - "@babel/helper-validator-identifier" "^7.22.20" - to-fast-properties "^2.0.0" - -"@bcoe/v8-coverage@^0.2.3": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" - integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== - -"@expo/config-plugins@^7.2.4": - version "7.2.5" - resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-7.2.5.tgz#b15f22878975fdc4ddcfa8cdc971937ddc4c0249" - integrity sha512-w+5ccu1IxBHgyQk9CPFKLZOk8yZQEyTjbJwOzESK1eR7QwosbcsLkN1c1WWUZYiCXwORu3UTwJYll4+X2xxJhQ== - dependencies: - "@expo/config-types" "^49.0.0-alpha.1" - "@expo/json-file" "~8.2.37" - "@expo/plist" "^0.0.20" - "@expo/sdk-runtime-versions" "^1.0.0" - "@react-native/normalize-color" "^2.0.0" - chalk "^4.1.2" - debug "^4.3.1" - find-up "~5.0.0" - getenv "^1.0.0" - glob "7.1.6" - resolve-from "^5.0.0" - semver "^7.5.3" - slash "^3.0.0" - xcode "^3.0.1" - xml2js "0.6.0" - -"@expo/config-types@^49.0.0-alpha.1": - version "49.0.0" - resolved "https://registry.yarnpkg.com/@expo/config-types/-/config-types-49.0.0.tgz#15ffef715285c06703f6fb7ec0cda853f645cc09" - integrity sha512-8eyREVi+K2acnMBe/rTIu1dOfyR2+AMnTLHlut+YpMV9OZPdeKV0Bs9BxAewGqBA2slslbQ9N39IS2CuTKpXkA== - -"@expo/json-file@~8.2.37": - version "8.2.37" - resolved "https://registry.yarnpkg.com/@expo/json-file/-/json-file-8.2.37.tgz#9c02d3b42134907c69cc0a027b18671b69344049" - integrity sha512-YaH6rVg11JoTS2P6LsW7ybS2CULjf40AbnAHw2F1eDPuheprNjARZMnyHFPkKv7GuxCy+B9GPcbOKgc4cgA80Q== - dependencies: - "@babel/code-frame" "~7.10.4" - json5 "^2.2.2" - write-file-atomic "^2.3.0" - -"@expo/plist@^0.0.20": - version "0.0.20" - resolved "https://registry.yarnpkg.com/@expo/plist/-/plist-0.0.20.tgz#a6b3124438031c02b762bad5a47b70584d3c0072" - integrity sha512-UXQ4LXCfTZ580LDHGJ5q62jSTwJFFJ1GqBu8duQMThiHKWbMJ+gajJh6rsB6EJ3aLUr9wcauxneL5LVRFxwBEA== - dependencies: - "@xmldom/xmldom" "~0.7.7" - base64-js "^1.2.3" - xmlbuilder "^14.0.0" - -"@expo/sdk-runtime-versions@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@expo/sdk-runtime-versions/-/sdk-runtime-versions-1.0.0.tgz#d7ebd21b19f1c6b0395e50d78da4416941c57f7c" - integrity sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ== - -"@hapi/hoek@^9.0.0": - version "9.3.0" - resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb" - integrity sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ== - -"@hapi/topo@^5.0.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012" - integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== - dependencies: - "@hapi/hoek" "^9.0.0" - -"@istanbuljs/load-nyc-config@^1.0.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" - integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== - dependencies: - camelcase "^5.3.1" - find-up "^4.1.0" - get-package-type "^0.1.0" - js-yaml "^3.13.1" - resolve-from "^5.0.0" - -"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" - integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== - -"@jest/console@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" - integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== - dependencies: - "@jest/types" "^29.6.3" - "@types/node" "*" - chalk "^4.0.0" - jest-message-util "^29.7.0" - jest-util "^29.7.0" - slash "^3.0.0" - -"@jest/core@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" - integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== - dependencies: - "@jest/console" "^29.7.0" - "@jest/reporters" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - ci-info "^3.2.0" - exit "^0.1.2" - graceful-fs "^4.2.9" - jest-changed-files "^29.7.0" - jest-config "^29.7.0" - jest-haste-map "^29.7.0" - jest-message-util "^29.7.0" - jest-regex-util "^29.6.3" - jest-resolve "^29.7.0" - jest-resolve-dependencies "^29.7.0" - jest-runner "^29.7.0" - jest-runtime "^29.7.0" - jest-snapshot "^29.7.0" - jest-util "^29.7.0" - jest-validate "^29.7.0" - jest-watcher "^29.7.0" - micromatch "^4.0.4" - pretty-format "^29.7.0" - slash "^3.0.0" - strip-ansi "^6.0.0" - -"@jest/create-cache-key-function@^29.2.1": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz#793be38148fab78e65f40ae30c36785f4ad859f0" - integrity sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA== - dependencies: - "@jest/types" "^29.6.3" - -"@jest/environment@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" - integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== - dependencies: - "@jest/fake-timers" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - jest-mock "^29.7.0" - -"@jest/expect-utils@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" - integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== - dependencies: - jest-get-type "^29.6.3" - -"@jest/expect@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" - integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== - dependencies: - expect "^29.7.0" - jest-snapshot "^29.7.0" - -"@jest/fake-timers@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" - integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== - dependencies: - "@jest/types" "^29.6.3" - "@sinonjs/fake-timers" "^10.0.2" - "@types/node" "*" - jest-message-util "^29.7.0" - jest-mock "^29.7.0" - jest-util "^29.7.0" - -"@jest/globals@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" - integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== - dependencies: - "@jest/environment" "^29.7.0" - "@jest/expect" "^29.7.0" - "@jest/types" "^29.6.3" - jest-mock "^29.7.0" - -"@jest/reporters@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" - integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== - dependencies: - "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" - "@jridgewell/trace-mapping" "^0.3.18" - "@types/node" "*" - chalk "^4.0.0" - collect-v8-coverage "^1.0.0" - exit "^0.1.2" - glob "^7.1.3" - graceful-fs "^4.2.9" - istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^6.0.0" - istanbul-lib-report "^3.0.0" - istanbul-lib-source-maps "^4.0.0" - istanbul-reports "^3.1.3" - jest-message-util "^29.7.0" - jest-util "^29.7.0" - jest-worker "^29.7.0" - slash "^3.0.0" - string-length "^4.0.1" - strip-ansi "^6.0.0" - v8-to-istanbul "^9.0.1" - -"@jest/schemas@^29.6.3": - version "29.6.3" - resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" - integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== - dependencies: - "@sinclair/typebox" "^0.27.8" - -"@jest/source-map@^29.6.3": - version "29.6.3" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" - integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== - dependencies: - "@jridgewell/trace-mapping" "^0.3.18" - callsites "^3.0.0" - graceful-fs "^4.2.9" - -"@jest/test-result@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" - integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== - dependencies: - "@jest/console" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/istanbul-lib-coverage" "^2.0.0" - collect-v8-coverage "^1.0.0" - -"@jest/test-sequencer@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" - integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== - dependencies: - "@jest/test-result" "^29.7.0" - graceful-fs "^4.2.9" - jest-haste-map "^29.7.0" - slash "^3.0.0" - -"@jest/transform@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" - integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== - dependencies: - "@babel/core" "^7.11.6" - "@jest/types" "^29.6.3" - "@jridgewell/trace-mapping" "^0.3.18" - babel-plugin-istanbul "^6.1.1" - chalk "^4.0.0" - convert-source-map "^2.0.0" - fast-json-stable-stringify "^2.1.0" - graceful-fs "^4.2.9" - jest-haste-map "^29.7.0" - jest-regex-util "^29.6.3" - jest-util "^29.7.0" - micromatch "^4.0.4" - pirates "^4.0.4" - slash "^3.0.0" - write-file-atomic "^4.0.2" - -"@jest/types@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" - integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^15.0.0" - chalk "^4.0.0" - -"@jest/types@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80" - integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^16.0.0" - chalk "^4.0.0" - -"@jest/types@^29.6.3": - version "29.6.3" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" - integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== - dependencies: - "@jest/schemas" "^29.6.3" - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^17.0.8" - chalk "^4.0.0" - -"@jridgewell/gen-mapping@^0.1.0": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" - integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== - dependencies: - "@jridgewell/set-array" "^1.0.0" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@jridgewell/gen-mapping@^0.3.0": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz#cf92a983c83466b8c0ce9124fadeaf09f7c66ea9" - integrity sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg== - dependencies: - "@jridgewell/set-array" "^1.0.0" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/gen-mapping@^0.3.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" - integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== - dependencies: - "@jridgewell/set-array" "^1.0.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/gen-mapping@^0.3.5": - version "0.3.8" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142" - integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA== - dependencies: - "@jridgewell/set-array" "^1.2.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.24" - -"@jridgewell/resolve-uri@^3.0.3": - version "3.0.7" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz#30cd49820a962aff48c8fffc5cd760151fca61fe" - integrity sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA== - -"@jridgewell/resolve-uri@^3.1.0": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" - integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== - -"@jridgewell/set-array@^1.0.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.1.tgz#36a6acc93987adcf0ba50c66908bd0b70de8afea" - integrity sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ== - -"@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== - -"@jridgewell/set-array@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" - integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== - -"@jridgewell/source-map@^0.3.3": - version "0.3.6" - resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a" - integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ== - dependencies: - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" - -"@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.13" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz#b6461fb0c2964356c469e115f504c95ad97ab88c" - integrity sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w== - -"@jridgewell/sourcemap-codec@^1.4.14": - version "1.4.15" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== - -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": - version "0.3.25" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" - integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - -"@jridgewell/trace-mapping@^0.3.17": - version "0.3.19" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811" - integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - -"@jridgewell/trace-mapping@^0.3.9": - version "0.3.13" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz#dcfe3e95f224c8fe97a87a5235defec999aa92ea" - integrity sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@react-native-community/cli-clean@11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-clean/-/cli-clean-11.4.1.tgz#0155a02e4158c8a61ba3d7a2b08f3ebebed81906" - integrity sha512-cwUbY3c70oBGv3FvQJWe2Qkq6m1+/dcEBonMDTYyH6i+6OrkzI4RkIGpWmbG1IS5JfE9ISUZkNL3946sxyWNkw== - dependencies: - "@react-native-community/cli-tools" "11.4.1" - chalk "^4.1.2" - execa "^5.0.0" - prompts "^2.4.0" - -"@react-native-community/cli-config@11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-config/-/cli-config-11.4.1.tgz#c27f91d2753f0f803cc79bbf299f19648a5d5627" - integrity sha512-sLdv1HFVqu5xNpeaR1+std0t7FFZaobpmpR0lFCOzKV7H/l611qS2Vo8zssmMK+oQbCs5JsX3SFPciODeIlaWA== - dependencies: - "@react-native-community/cli-tools" "11.4.1" - chalk "^4.1.2" - cosmiconfig "^5.1.0" - deepmerge "^4.3.0" - glob "^7.1.3" - joi "^17.2.1" - -"@react-native-community/cli-debugger-ui@11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-11.4.1.tgz#783cc276e1360baf8235dc8c6ebbbce0fe01d944" - integrity sha512-+pgIjGNW5TrJF37XG3djIOzP+WNoPp67to/ggDhrshuYgpymfb9XpDVsURJugy0Sy3RViqb83kQNK765QzTIvw== - dependencies: - serve-static "^1.13.1" - -"@react-native-community/cli-doctor@11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-doctor/-/cli-doctor-11.4.1.tgz#516ef5932de3e12989695e7cb7aba82b81e7b2de" - integrity sha512-O6oPiRsl8pdkcyNktpzvJAXUqdocoY4jh7Tt7wA69B1JKCJA7aPCecwJgpUZb63ZYoxOtRtYM3BYQKzRMLIuUw== - dependencies: - "@react-native-community/cli-config" "11.4.1" - "@react-native-community/cli-platform-android" "11.4.1" - "@react-native-community/cli-platform-ios" "11.4.1" - "@react-native-community/cli-tools" "11.4.1" - chalk "^4.1.2" - command-exists "^1.2.8" - envinfo "^7.7.2" - execa "^5.0.0" - hermes-profile-transformer "^0.0.6" - node-stream-zip "^1.9.1" - ora "^5.4.1" - prompts "^2.4.0" - semver "^7.5.2" - strip-ansi "^5.2.0" - sudo-prompt "^9.0.0" - wcwidth "^1.0.1" - yaml "^2.2.1" - -"@react-native-community/cli-hermes@11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-hermes/-/cli-hermes-11.4.1.tgz#abf487ae8ab53c66f6f1178bcd37ecbbbac9fb5c" - integrity sha512-1VAjwcmv+i9BJTMMVn5Grw7AcgURhTyfHVghJ1YgBE2euEJxPuqPKSxP54wBOQKnWUwsuDQAtQf+jPJoCxJSSA== - dependencies: - "@react-native-community/cli-platform-android" "11.4.1" - "@react-native-community/cli-tools" "11.4.1" - chalk "^4.1.2" - hermes-profile-transformer "^0.0.6" - -"@react-native-community/cli-platform-android@11.4.1", "@react-native-community/cli-platform-android@^11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-11.4.1.tgz#ec5fc97e87834f2e33cb0d34dcef6c17b20f60fc" - integrity sha512-VMmXWIzk0Dq5RAd+HIEa3Oe7xl2jso7+gOr6E2HALF4A3fCKUjKZQ6iK2t6AfnY04zftvaiKw6zUXtrfl52AVQ== - dependencies: - "@react-native-community/cli-tools" "11.4.1" - chalk "^4.1.2" - execa "^5.0.0" - glob "^7.1.3" - logkitty "^0.7.1" - -"@react-native-community/cli-platform-ios@11.4.1", "@react-native-community/cli-platform-ios@^11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-11.4.1.tgz#12d72741273b684734d5ed021415b7f543a6f009" - integrity sha512-RPhwn+q3IY9MpWc9w/Qmzv03mo8sXdah2eSZcECgweqD5SHWtOoRCUt11zM8jASpAQ8Tm5Je7YE9bHvdwGl4hA== - dependencies: - "@react-native-community/cli-tools" "11.4.1" - chalk "^4.1.2" - execa "^5.0.0" - fast-xml-parser "^4.0.12" - glob "^7.1.3" - ora "^5.4.1" - -"@react-native-community/cli-plugin-metro@11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-11.4.1.tgz#8d51c59a9a720f99150d4153e757d5d1d1dabd22" - integrity sha512-JxbIqknYcQ5Z4rWROtu5LNakLfMiKoWcMoPqIrBLrV5ILm1XUJj1/8fATCcotZqV3yzB3SCJ3RrhKx7dQ3YELw== - dependencies: - "@react-native-community/cli-server-api" "11.4.1" - "@react-native-community/cli-tools" "11.4.1" - chalk "^4.1.2" - execa "^5.0.0" - metro "^0.76.9" - metro-config "^0.76.9" - metro-core "^0.76.9" - metro-react-native-babel-transformer "^0.76.9" - metro-resolver "^0.76.9" - metro-runtime "^0.76.9" - readline "^1.3.0" - -"@react-native-community/cli-server-api@11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-server-api/-/cli-server-api-11.4.1.tgz#3dda094c4ab2369db34fe991c320e3cd78f097b3" - integrity sha512-isxXE8X5x+C4kN90yilD08jaLWD34hfqTfn/Xbl1u/igtdTsCaQGvWe9eaFamrpWFWTpVtj6k+vYfy8AtYSiKA== - dependencies: - "@react-native-community/cli-debugger-ui" "11.4.1" - "@react-native-community/cli-tools" "11.4.1" - compression "^1.7.1" - connect "^3.6.5" - errorhandler "^1.5.1" - nocache "^3.0.1" - pretty-format "^26.6.2" - serve-static "^1.13.1" - ws "^7.5.1" - -"@react-native-community/cli-tools@11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-11.4.1.tgz#f6c69967e077b10cd8a884a83e53eb199dd9ee9f" - integrity sha512-GuQIuY/kCPfLeXB1aiPZ5HvF+e/wdO42AYuNEmT7FpH/0nAhdTxA9qjL8m3vatDD2/YK7WNOSVNsl2UBZuOISg== - dependencies: - appdirsjs "^1.2.4" - chalk "^4.1.2" - find-up "^5.0.0" - mime "^2.4.1" - node-fetch "^2.6.0" - open "^6.2.0" - ora "^5.4.1" - semver "^7.5.2" - shell-quote "^1.7.3" - -"@react-native-community/cli-types@11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-types/-/cli-types-11.4.1.tgz#3842dc37ba3b09f929b485bcbd8218de19349ac2" - integrity sha512-B3q9A5BCneLDSoK/iSJ06MNyBn1qTxjdJeOgeS3MiCxgJpPcxyn/Yrc6+h0Cu9T9sgWj/dmectQPYWxtZeo5VA== - dependencies: - joi "^17.2.1" - -"@react-native-community/cli@^11.4.1": - version "11.4.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-11.4.1.tgz#9a6346486622860dad721da406df70e29a45491f" - integrity sha512-NdAageVMtNhtvRsrq4NgJf5Ey2nA1CqmLvn7PhSawg+aIzMKmZuzWxGVwr9CoPGyjvNiqJlCWrLGR7NzOyi/sA== - dependencies: - "@react-native-community/cli-clean" "11.4.1" - "@react-native-community/cli-config" "11.4.1" - "@react-native-community/cli-debugger-ui" "11.4.1" - "@react-native-community/cli-doctor" "11.4.1" - "@react-native-community/cli-hermes" "11.4.1" - "@react-native-community/cli-plugin-metro" "11.4.1" - "@react-native-community/cli-server-api" "11.4.1" - "@react-native-community/cli-tools" "11.4.1" - "@react-native-community/cli-types" "11.4.1" - chalk "^4.1.2" - commander "^9.4.1" - execa "^5.0.0" - find-up "^4.1.0" - fs-extra "^8.1.0" - graceful-fs "^4.1.3" - prompts "^2.4.0" - semver "^7.5.2" - -"@react-native/assets-registry@^0.72.0": - version "0.72.0" - resolved "https://registry.yarnpkg.com/@react-native/assets-registry/-/assets-registry-0.72.0.tgz#c82a76a1d86ec0c3907be76f7faf97a32bbed05d" - integrity sha512-Im93xRJuHHxb1wniGhBMsxLwcfzdYreSZVQGDoMJgkd6+Iky61LInGEHnQCTN0fKNYF1Dvcofb4uMmE1RQHXHQ== - -"@react-native/codegen@^0.72.8": - version "0.72.8" - resolved "https://registry.yarnpkg.com/@react-native/codegen/-/codegen-0.72.8.tgz#0593f628e1310f430450a9479fbb4be35e7b63d6" - integrity sha512-jQCcBlXV7B7ap5VlHhwIPieYz89yiRgwd2FPUBu+unz+kcJ6pAiB2U8RdLDmyIs8fiWd+Vq1xxaWs4TR329/ng== - dependencies: - "@babel/parser" "^7.20.0" - flow-parser "^0.206.0" - glob "^7.1.1" - invariant "^2.2.4" - jscodeshift "^0.14.0" - mkdirp "^0.5.1" - nullthrows "^1.1.1" - -"@react-native/gradle-plugin@^0.72.11": - version "0.72.11" - resolved "https://registry.yarnpkg.com/@react-native/gradle-plugin/-/gradle-plugin-0.72.11.tgz#c063ef12778706611de7a1e42b74b14d9405fb9f" - integrity sha512-P9iRnxiR2w7EHcZ0mJ+fmbPzMby77ZzV6y9sJI3lVLJzF7TLSdbwcQyD3lwMsiL+q5lKUHoZJS4sYmih+P2HXw== - -"@react-native/js-polyfills@^0.72.1": - version "0.72.1" - resolved "https://registry.yarnpkg.com/@react-native/js-polyfills/-/js-polyfills-0.72.1.tgz#905343ef0c51256f128256330fccbdb35b922291" - integrity sha512-cRPZh2rBswFnGt5X5EUEPs0r+pAsXxYsifv/fgy9ZLQokuT52bPH+9xjDR+7TafRua5CttGW83wP4TntRcWNDA== - -"@react-native/normalize-color@^2.0.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@react-native/normalize-color/-/normalize-color-2.1.0.tgz#939b87a9849e81687d3640c5efa2a486ac266f91" - integrity sha512-Z1jQI2NpdFJCVgpY+8Dq/Bt3d+YUi1928Q+/CZm/oh66fzM0RUl54vvuXlPJKybH4pdCZey1eDTPaLHkMPNgWA== - -"@react-native/normalize-colors@<0.73.0", "@react-native/normalize-colors@^0.72.0": - version "0.72.0" - resolved "https://registry.yarnpkg.com/@react-native/normalize-colors/-/normalize-colors-0.72.0.tgz#14294b7ed3c1d92176d2a00df48456e8d7d62212" - integrity sha512-285lfdqSXaqKuBbbtP9qL2tDrfxdOFtIMvkKadtleRQkdOxx+uzGvFr82KHmc/sSiMtfXGp7JnFYWVh4sFl7Yw== - -"@react-native/virtualized-lists@^0.72.8": - version "0.72.8" - resolved "https://registry.yarnpkg.com/@react-native/virtualized-lists/-/virtualized-lists-0.72.8.tgz#a2c6a91ea0f1d40eb5a122fb063daedb92ed1dc3" - integrity sha512-J3Q4Bkuo99k7mu+jPS9gSUSgq+lLRSI/+ahXNwV92XgJ/8UgOTxu2LPwhJnBk/sQKxq7E8WkZBnBiozukQMqrw== - dependencies: - invariant "^2.2.4" - nullthrows "^1.1.1" - -"@sideway/address@^4.1.3": - version "4.1.4" - resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0" - integrity sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw== - dependencies: - "@hapi/hoek" "^9.0.0" - -"@sideway/formula@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.1.tgz#80fcbcbaf7ce031e0ef2dd29b1bfc7c3f583611f" - integrity sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg== - -"@sideway/pinpoint@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" - integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== - -"@sinclair/typebox@^0.27.8": - version "0.27.8" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" - integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== - -"@sinonjs/commons@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" - integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== - dependencies: - type-detect "4.0.8" - -"@sinonjs/fake-timers@^10.0.2": - version "10.3.0" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" - integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== - dependencies: - "@sinonjs/commons" "^3.0.0" - -"@tsconfig/react-native@^3.0.0": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@tsconfig/react-native/-/react-native-3.0.5.tgz#c4971b1eca2e8cdf7b0d25f40193a782039c1abd" - integrity sha512-0+pmYzHccvwWpFz2Tv5AJxp6UroLALmAy+SX34tKlwaCie1mNbtCv6uOJp7x8pKchgNA9/n6BGrx7uLQvw8p9A== - -"@types/babel__core@^7.1.14": - version "7.1.19" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.19.tgz#7b497495b7d1b4812bdb9d02804d0576f43ee460" - integrity sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - "@types/babel__generator" "*" - "@types/babel__template" "*" - "@types/babel__traverse" "*" - -"@types/babel__generator@*": - version "7.6.4" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" - integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== - dependencies: - "@babel/types" "^7.0.0" - -"@types/babel__template@*": - version "7.4.1" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" - integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": - version "7.17.1" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.17.1.tgz#1a0e73e8c28c7e832656db372b779bfd2ef37314" - integrity sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA== - dependencies: - "@babel/types" "^7.3.0" - -"@types/graceful-fs@^4.1.3": - version "4.1.9" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" - integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== - dependencies: - "@types/node" "*" - -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" - integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== - -"@types/istanbul-lib-report@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" - integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== - dependencies: - "@types/istanbul-lib-coverage" "*" - -"@types/istanbul-reports@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" - integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== - dependencies: - "@types/istanbul-lib-report" "*" - -"@types/jest@^29.2.1": - version "29.5.14" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.14.tgz#2b910912fa1d6856cadcd0c1f95af7df1d6049e5" - integrity sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ== - dependencies: - expect "^29.0.0" - pretty-format "^29.0.0" - -"@types/node@*": - version "17.0.35" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.35.tgz#635b7586086d51fb40de0a2ec9d1014a5283ba4a" - integrity sha512-vu1SrqBjbbZ3J6vwY17jBs8Sr/BKA+/a/WtjRG+whKg1iuLFOosq872EXS0eXWILdO36DHQQeku/ZcL6hz2fpg== - -"@types/prop-types@*": - version "15.7.5" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" - integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== - -"@types/react@^18.0.24": - version "18.3.18" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.18.tgz#9b382c4cd32e13e463f97df07c2ee3bbcd26904b" - integrity sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ== - dependencies: - "@types/prop-types" "*" - csstype "^3.0.2" - -"@types/stack-utils@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" - integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== - -"@types/yargs-parser@*": - version "21.0.0" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" - integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== - -"@types/yargs@^15.0.0": - version "15.0.14" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.14.tgz#26d821ddb89e70492160b66d10a0eb6df8f6fb06" - integrity sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ== - dependencies: - "@types/yargs-parser" "*" - -"@types/yargs@^16.0.0": - version "16.0.4" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977" - integrity sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw== - dependencies: - "@types/yargs-parser" "*" - -"@types/yargs@^17.0.8": - version "17.0.33" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.33.tgz#8c32303da83eec050a84b3c7ae7b9f922d13e32d" - integrity sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA== - dependencies: - "@types/yargs-parser" "*" - -"@xmldom/xmldom@~0.7.7": - version "0.7.11" - resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.11.tgz#adecc134521274711d071d5b0200907cc83b38ee" - integrity sha512-UDi3g6Jss/W5FnSzO9jCtQwEpfymt0M+sPPlmLhDH6h2TJ8j4ESE/LpmNPBij15J5NKkk4/cg/qoVMdWI3vnlQ== - -abort-controller@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" - integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== - dependencies: - event-target-shim "^5.0.0" - -accepts@^1.3.7, accepts@~1.3.5, accepts@~1.3.7: - version "1.3.8" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" - integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== - dependencies: - mime-types "~2.1.34" - negotiator "0.6.3" - -acorn@^8.8.2: - version "8.14.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" - integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== - -anser@^1.4.9: - version "1.4.10" - resolved "https://registry.yarnpkg.com/anser/-/anser-1.4.10.tgz#befa3eddf282684bd03b63dcda3927aef8c2e35b" - integrity sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww== - -ansi-escapes@^4.2.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== - dependencies: - type-fest "^0.21.3" - -ansi-fragments@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/ansi-fragments/-/ansi-fragments-0.2.1.tgz#24409c56c4cc37817c3d7caa99d8969e2de5a05e" - integrity sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w== - dependencies: - colorette "^1.0.7" - slice-ansi "^2.0.0" - strip-ansi "^5.0.0" - -ansi-regex@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" - integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== - -ansi-regex@^5.0.0, ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-styles@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" - integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== - -anymatch@^3.0.3: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -appdirsjs@^1.2.4: - version "1.2.6" - resolved "https://registry.yarnpkg.com/appdirsjs/-/appdirsjs-1.2.6.tgz#fccf9ee543315492867cacfcfd4a2b32257d30ac" - integrity sha512-D8wJNkqMCeQs3kLasatELsddox/Xqkhp+J07iXGyL54fVN7oc+nmNfYzGuCs1IEP6uBw+TfpuO3JKwc+lECy4w== - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -asap@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== - -ast-types@0.15.2: - version "0.15.2" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.15.2.tgz#39ae4809393c4b16df751ee563411423e85fb49d" - integrity sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg== - dependencies: - tslib "^2.0.1" - -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - -async-limiter@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" - integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== - -async@^3.2.2: - version "3.2.4" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" - integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== - -babel-core@^7.0.0-bridge.0: - version "7.0.0-bridge.0" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece" - integrity sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg== - -babel-jest@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" - integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== - dependencies: - "@jest/transform" "^29.7.0" - "@types/babel__core" "^7.1.14" - babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^29.6.3" - chalk "^4.0.0" - graceful-fs "^4.2.9" - slash "^3.0.0" - -babel-plugin-dynamic-import-node@^2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" - integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== - dependencies: - object.assign "^4.1.0" - -babel-plugin-istanbul@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" - integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@istanbuljs/load-nyc-config" "^1.0.0" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-instrument "^5.0.4" - test-exclude "^6.0.0" - -babel-plugin-jest-hoist@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" - integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== - dependencies: - "@babel/template" "^7.3.3" - "@babel/types" "^7.3.3" - "@types/babel__core" "^7.1.14" - "@types/babel__traverse" "^7.0.6" - -babel-plugin-polyfill-corejs2@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz#440f1b70ccfaabc6b676d196239b138f8a2cfba5" - integrity sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w== - dependencies: - "@babel/compat-data" "^7.13.11" - "@babel/helper-define-polyfill-provider" "^0.3.1" - semver "^6.1.1" - -babel-plugin-polyfill-corejs3@^0.5.0: - version "0.5.2" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz#aabe4b2fa04a6e038b688c5e55d44e78cd3a5f72" - integrity sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.1" - core-js-compat "^3.21.0" - -babel-plugin-polyfill-regenerator@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz#2c0678ea47c75c8cc2fbb1852278d8fb68233990" - integrity sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.1" - -babel-plugin-syntax-trailing-function-commas@^7.0.0-beta.0: - version "7.0.0-beta.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz#aa213c1435e2bffeb6fca842287ef534ad05d5cf" - integrity sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ== - -babel-plugin-transform-flow-enums@^0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-enums/-/babel-plugin-transform-flow-enums-0.0.2.tgz#d1d0cc9bdc799c850ca110d0ddc9f21b9ec3ef25" - integrity sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ== - dependencies: - "@babel/plugin-syntax-flow" "^7.12.1" - -babel-preset-current-node-syntax@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" - integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== - dependencies: - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-bigint" "^7.8.3" - "@babel/plugin-syntax-class-properties" "^7.8.3" - "@babel/plugin-syntax-import-meta" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-top-level-await" "^7.8.3" - -babel-preset-fbjs@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/babel-preset-fbjs/-/babel-preset-fbjs-3.4.0.tgz#38a14e5a7a3b285a3f3a86552d650dca5cf6111c" - integrity sha512-9ywCsCvo1ojrw0b+XYk7aFvTH6D9064t0RIL1rtMf3nsa02Xw41MS7sZw216Im35xj/UY0PDBQsa1brUDDF1Ow== - dependencies: - "@babel/plugin-proposal-class-properties" "^7.0.0" - "@babel/plugin-proposal-object-rest-spread" "^7.0.0" - "@babel/plugin-syntax-class-properties" "^7.0.0" - "@babel/plugin-syntax-flow" "^7.0.0" - "@babel/plugin-syntax-jsx" "^7.0.0" - "@babel/plugin-syntax-object-rest-spread" "^7.0.0" - "@babel/plugin-transform-arrow-functions" "^7.0.0" - "@babel/plugin-transform-block-scoped-functions" "^7.0.0" - "@babel/plugin-transform-block-scoping" "^7.0.0" - "@babel/plugin-transform-classes" "^7.0.0" - "@babel/plugin-transform-computed-properties" "^7.0.0" - "@babel/plugin-transform-destructuring" "^7.0.0" - "@babel/plugin-transform-flow-strip-types" "^7.0.0" - "@babel/plugin-transform-for-of" "^7.0.0" - "@babel/plugin-transform-function-name" "^7.0.0" - "@babel/plugin-transform-literals" "^7.0.0" - "@babel/plugin-transform-member-expression-literals" "^7.0.0" - "@babel/plugin-transform-modules-commonjs" "^7.0.0" - "@babel/plugin-transform-object-super" "^7.0.0" - "@babel/plugin-transform-parameters" "^7.0.0" - "@babel/plugin-transform-property-literals" "^7.0.0" - "@babel/plugin-transform-react-display-name" "^7.0.0" - "@babel/plugin-transform-react-jsx" "^7.0.0" - "@babel/plugin-transform-shorthand-properties" "^7.0.0" - "@babel/plugin-transform-spread" "^7.0.0" - "@babel/plugin-transform-template-literals" "^7.0.0" - babel-plugin-syntax-trailing-function-commas "^7.0.0-beta.0" - -babel-preset-jest@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" - integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== - dependencies: - babel-plugin-jest-hoist "^29.6.3" - babel-preset-current-node-syntax "^1.0.0" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -base64-js@^1.1.2, base64-js@^1.2.3, base64-js@^1.3.1, base64-js@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -big-integer@1.6.x: - version "1.6.51" - resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" - integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== - -bl@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" - integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== - dependencies: - buffer "^5.5.0" - inherits "^2.0.4" - readable-stream "^3.4.0" - -bplist-creator@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/bplist-creator/-/bplist-creator-0.1.0.tgz#018a2d1b587f769e379ef5519103730f8963ba1e" - integrity sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg== - dependencies: - stream-buffers "2.2.x" - -bplist-parser@0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/bplist-parser/-/bplist-parser-0.3.1.tgz#e1c90b2ca2a9f9474cc72f6862bbf3fee8341fd1" - integrity sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA== - dependencies: - big-integer "1.6.x" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" - integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== - dependencies: - fill-range "^7.1.1" - -browserslist@^4.20.2, browserslist@^4.20.3: - version "4.20.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.3.tgz#eb7572f49ec430e054f56d52ff0ebe9be915f8bf" - integrity sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg== - dependencies: - caniuse-lite "^1.0.30001332" - electron-to-chromium "^1.4.118" - escalade "^3.1.1" - node-releases "^2.0.3" - picocolors "^1.0.0" - -browserslist@^4.24.0: - version "4.24.4" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.4.tgz#c6b2865a3f08bcb860a0e827389003b9fe686e4b" - integrity sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A== - dependencies: - caniuse-lite "^1.0.30001688" - electron-to-chromium "^1.5.73" - node-releases "^2.0.19" - update-browserslist-db "^1.1.1" - -bser@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" - integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== - dependencies: - node-int64 "^0.4.0" - -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - -buffer@^5.5.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - -buffer@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - -bytes@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" - integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== - -call-bind@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" - -caller-callsite@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" - integrity sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ== - dependencies: - callsites "^2.0.0" - -caller-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" - integrity sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A== - dependencies: - caller-callsite "^2.0.0" - -callsites@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" - integrity sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ== - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -camelcase@^5.0.0, camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -camelcase@^6.2.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" - integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== - -caniuse-lite@^1.0.30001332: - version "1.0.30001342" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001342.tgz#87152b1e3b950d1fbf0093e23f00b6c8e8f1da96" - integrity sha512-bn6sOCu7L7jcbBbyNhLg0qzXdJ/PMbybZTH/BA6Roet9wxYRm6Tr9D0s0uhLkOZ6MSG+QU6txUgdpr3MXIVqjA== - -caniuse-lite@^1.0.30001688: - version "1.0.30001695" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001695.tgz#39dfedd8f94851132795fdf9b79d29659ad9c4d4" - integrity sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw== - -chalk@^2.0.0, chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -char-regex@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" - integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== - -ci-info@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" - integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== - -ci-info@^3.2.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.1.tgz#58331f6f472a25fe3a50a351ae3052936c2c7f32" - integrity sha512-SXgeMX9VwDe7iFFaEWkA5AstuER9YKqy4EhHqr4DVqkwmD9rpVimkMKWHdjn30Ja45txyjhSn63lVX69eVCckg== - -cjs-module-lexer@^1.0.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" - integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== - -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - -cli-spinners@^2.5.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" - integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== - -cliui@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" - integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^6.2.0" - -cliui@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" - integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.1" - wrap-ansi "^7.0.0" - -clone-deep@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" - integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== - dependencies: - is-plain-object "^2.0.4" - kind-of "^6.0.2" - shallow-clone "^3.0.0" - -clone@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= - -collect-v8-coverage@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" - integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -colorette@^1.0.7: - version "1.4.0" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" - integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== - -command-exists@^1.2.8: - version "1.2.9" - resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69" - integrity sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== - -commander@^2.20.0: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -commander@^9.4.1: - version "9.5.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" - integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== - -commander@~2.13.0: - version "2.13.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" - integrity sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA== - -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= - -compressible@~2.0.16: - version "2.0.18" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" - integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== - dependencies: - mime-db ">= 1.43.0 < 2" - -compression@^1.7.1: - version "1.7.4" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" - integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== - dependencies: - accepts "~1.3.5" - bytes "3.0.0" - compressible "~2.0.16" - debug "2.6.9" - on-headers "~1.0.2" - safe-buffer "5.1.2" - vary "~1.1.2" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -connect@^3.6.5: - version "3.7.0" - resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8" - integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ== - dependencies: - debug "2.6.9" - finalhandler "1.1.2" - parseurl "~1.3.3" - utils-merge "1.0.1" - -convert-source-map@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" - integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== - dependencies: - safe-buffer "~5.1.1" - -convert-source-map@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" - integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== - -core-js-compat@^3.21.0: - version "3.22.7" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.22.7.tgz#8359eb66ecbf726dd0cfced8e48d5e73f3224239" - integrity sha512-uI9DAQKKiiE/mclIC5g4AjRpio27g+VMRhe6rQoz+q4Wm4L6A/fJhiLtBw+sfOpDG9wZ3O0pxIw7GbfOlBgjOA== - dependencies: - browserslist "^4.20.3" - semver "7.0.0" - -core-util-is@~1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" - integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== - -cosmiconfig@^5.0.5, cosmiconfig@^5.1.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" - integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== - dependencies: - import-fresh "^2.0.0" - is-directory "^0.3.1" - js-yaml "^3.13.1" - parse-json "^4.0.0" - -create-jest@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" - integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== - dependencies: - "@jest/types" "^29.6.3" - chalk "^4.0.0" - exit "^0.1.2" - graceful-fs "^4.2.9" - jest-config "^29.7.0" - jest-util "^29.7.0" - prompts "^2.0.1" - -cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -csstype@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.0.tgz#4ddcac3718d787cf9df0d1b7d15033925c8f29f2" - integrity sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA== - -dayjs@^1.8.15: - version "1.11.2" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.2.tgz#fa0f5223ef0d6724b3d8327134890cfe3d72fbe5" - integrity sha512-F4LXf1OeU9hrSYRPTTj/6FbO4HTjPKXvEIC1P2kcnFurViINCVk3ZV0xAS3XVx9MkMsXbbqlK6hjseaYbgKEHw== - -debug@2.6.9, debug@^2.2.0: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= - -dedent@^1.0.0: - version "1.5.3" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a" - integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== - -deepmerge@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" - integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== - -deepmerge@^4.3.0: - version "4.3.1" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" - integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== - -defaults@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" - integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= - dependencies: - clone "^1.0.2" - -define-properties@^1.1.3: - version "1.1.4" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" - integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== - dependencies: - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - -denodeify@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/denodeify/-/denodeify-1.2.1.tgz#3a36287f5034e699e7577901052c2e6c94251631" - integrity sha1-OjYof1A05pnnV3kBBSwubJQlFjE= - -depd@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" - integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== - -deprecated-react-native-prop-types@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-4.2.3.tgz#0ef845c1a80ef1636bd09060e4cdf70f9727e5ad" - integrity sha512-2rLTiMKidIFFYpIVM69UnQKngLqQfL6I11Ch8wGSBftS18FUXda+o2we2950X+1dmbgps28niI3qwyH4eX3Z1g== - dependencies: - "@react-native/normalize-colors" "<0.73.0" - invariant "^2.2.4" - prop-types "^15.8.1" - -destroy@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" - integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== - -detect-newline@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" - integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== - -diff-sequences@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" - integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= - -electron-to-chromium@^1.4.118: - version "1.4.138" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.138.tgz#3ec41ca589aaf505dfe2034fde913329af801730" - integrity sha512-IOyp2Seq3w4QLln+yZWcMF3VXhhduz4bwg9gfI+CnP5TkzwNXQ8FCZuwwPsnes73AfWdf5J2n2OXdUwDUspDPQ== - -electron-to-chromium@^1.5.73: - version "1.5.88" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.88.tgz#cdb6e2dda85e6521e8d7d3035ba391c8848e073a" - integrity sha512-K3C2qf1o+bGzbilTDCTBhTQcMS9KW60yTAaTeeXsfvQuTDDwlokLam/AdqlqcSy9u4UainDgsHV23ksXAOgamw== - -emittery@^0.13.1: - version "0.13.1" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" - integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= - -envinfo@^7.7.2: - version "7.8.1" - resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" - integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== - -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -error-stack-parser@^2.0.6: - version "2.0.7" - resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.0.7.tgz#b0c6e2ce27d0495cf78ad98715e0cad1219abb57" - integrity sha512-chLOW0ZGRf4s8raLrDxa5sdkvPec5YdvwbFnqJme4rk0rFajP8mPtrDL1+I+CwrQDCjswDA5sREX7jYQDQs9vA== - dependencies: - stackframe "^1.1.1" - -errorhandler@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/errorhandler/-/errorhandler-1.5.1.tgz#b9ba5d17cf90744cd1e851357a6e75bf806a9a91" - integrity sha512-rcOwbfvP1WTViVoUjcfZicVzjhjTuhSMntHh6mW3IrEiyE6mJyXvsToJUJGlGlw/2xU9P5whlWNGlIDVeCiT4A== - dependencies: - accepts "~1.3.7" - escape-html "~1.0.3" - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -escalade@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" - integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== - -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -escape-string-regexp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" - integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== - -esprima@^4.0.0, esprima@~4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= - -event-target-shim@^5.0.0, event-target-shim@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" - integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== - -execa@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - -exit@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= - -expect@^29.0.0, expect@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" - integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== - dependencies: - "@jest/expect-utils" "^29.7.0" - jest-get-type "^29.6.3" - jest-matcher-utils "^29.7.0" - jest-message-util "^29.7.0" - jest-util "^29.7.0" - -fast-json-stable-stringify@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-xml-parser@^4.0.12: - version "4.5.1" - resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.5.1.tgz#a7e665ff79b7919100a5202f23984b6150f9b31e" - integrity sha512-y655CeyUQ+jj7KBbYMc4FG01V8ZQqjN+gDYGJ50RtfsUB8iG9AmwmwoAgeKLJdmueKKMrH1RJ7yXHTSoczdv5w== - dependencies: - strnum "^1.0.5" - -fb-watchman@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" - integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== - dependencies: - bser "2.1.1" - -fill-range@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" - integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== - dependencies: - to-regex-range "^5.0.1" - -finalhandler@1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" - integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.3" - statuses "~1.5.0" - unpipe "~1.0.0" - -find-cache-dir@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" - integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== - dependencies: - commondir "^1.0.1" - make-dir "^2.0.0" - pkg-dir "^3.0.0" - -find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - -find-up@^4.0.0, find-up@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -find-up@^5.0.0, find-up@~5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - -flow-enums-runtime@^0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/flow-enums-runtime/-/flow-enums-runtime-0.0.5.tgz#95884bfcc82edaf27eef7e1dd09732331cfbafbc" - integrity sha512-PSZF9ZuaZD03sT9YaIs0FrGJ7lSUw7rHZIex+73UYVXg46eL/wxN5PaVcPJFudE2cJu5f0fezitV5aBkLHPUOQ== - -flow-parser@0.*: - version "0.178.1" - resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.178.1.tgz#4efe62b3c551c615411bd4a75031c881ff53a7da" - integrity sha512-TOvOfZVOhCsKAVU2E4QgFD5vmmF/JWl4bX77H4aYoq8No1mZdtUV8GW6wv03l8N3dmlRqAC5rZcDQ5e8aLDBOg== - -flow-parser@^0.206.0: - version "0.206.0" - resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.206.0.tgz#f4f794f8026535278393308e01ea72f31000bfef" - integrity sha512-HVzoK3r6Vsg+lKvlIZzaWNBVai+FXTX1wdYhz/wVlH13tb/gOdLXmlTqy6odmTBhT5UoWUbq0k8263Qhr9d88w== - -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= - -fs-extra@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - -fsevents@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -get-caller-file@^2.0.1, get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - -get-package-type@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" - integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== - -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - -getenv@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/getenv/-/getenv-1.0.0.tgz#874f2e7544fbca53c7a4738f37de8605c3fcfc31" - integrity sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg== - -glob@7.1.6: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.1.1, glob@^7.1.3, glob@^7.1.4: - version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -graceful-fs@^4.1.11, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9: - version "4.2.10" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" - integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-property-descriptors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" - integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== - dependencies: - get-intrinsic "^1.1.1" - -has-symbols@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== - -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -hermes-estree@0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.12.0.tgz#8a289f9aee854854422345e6995a48613bac2ca8" - integrity sha512-+e8xR6SCen0wyAKrMT3UD0ZCCLymKhRgjEB5sS28rKiFir/fXgLoeRilRUssFCILmGHb+OvHDUlhxs0+IEyvQw== - -hermes-parser@0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.12.0.tgz#114dc26697cfb41a6302c215b859b74224383773" - integrity sha512-d4PHnwq6SnDLhYl3LHNHvOg7nQ6rcI7QVil418REYksv0Mh3cEkHDcuhGxNQ3vgnLSLl4QSvDrFCwQNYdpWlzw== - dependencies: - hermes-estree "0.12.0" - -hermes-profile-transformer@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/hermes-profile-transformer/-/hermes-profile-transformer-0.0.6.tgz#bd0f5ecceda80dd0ddaae443469ab26fb38fc27b" - integrity sha512-cnN7bQUm65UWOy6cbGcCcZ3rpwW8Q/j4OP5aWRhEry4Z2t2aR1cjrbp0BS+KiBN0smvP1caBgAuxutvyvJILzQ== - dependencies: - source-map "^0.7.3" - -html-escaper@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" - integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== - -http-errors@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" - integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== - dependencies: - depd "2.0.0" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses "2.0.1" - toidentifier "1.0.1" - -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - -ieee754@^1.1.13, ieee754@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -image-size@^1.0.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/image-size/-/image-size-1.2.0.tgz#312af27a2ff4ff58595ad00b9344dd684c910df6" - integrity sha512-4S8fwbO6w3GeCVN6OPtA9I5IGKkcDMPcKndtUlpJuCwu7JLjtj7JZpwqLuyY2nrmQT3AWsCJLSKPsc2mPBSl3w== - dependencies: - queue "6.0.2" - -import-fresh@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" - integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= - dependencies: - caller-path "^2.0.0" - resolve-from "^3.0.0" - -import-local@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" - integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== - dependencies: - pkg-dir "^4.2.0" - resolve-cwd "^3.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -invariant@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - -is-core-module@^2.8.1: - version "2.9.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69" - integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== - dependencies: - has "^1.0.3" - -is-directory@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" - integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-generator-fn@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" - integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== - -is-interactive@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" - integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -is-unicode-supported@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" - integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== - -is-wsl@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" - integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= - -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= - -istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" - integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== - -istanbul-lib-instrument@^5.0.4: - version "5.2.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz#31d18bdd127f825dd02ea7bfdfd906f8ab840e9f" - integrity sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A== - dependencies: - "@babel/core" "^7.12.3" - "@babel/parser" "^7.14.7" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.2.0" - semver "^6.3.0" - -istanbul-lib-instrument@^6.0.0: - version "6.0.3" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" - integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== - dependencies: - "@babel/core" "^7.23.9" - "@babel/parser" "^7.23.9" - "@istanbuljs/schema" "^0.1.3" - istanbul-lib-coverage "^3.2.0" - semver "^7.5.4" - -istanbul-lib-report@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" - integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== - dependencies: - istanbul-lib-coverage "^3.0.0" - make-dir "^3.0.0" - supports-color "^7.1.0" - -istanbul-lib-source-maps@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" - integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== - dependencies: - debug "^4.1.1" - istanbul-lib-coverage "^3.0.0" - source-map "^0.6.1" - -istanbul-reports@^3.1.3: - version "3.1.4" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.4.tgz#1b6f068ecbc6c331040aab5741991273e609e40c" - integrity sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw== - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - -jest-changed-files@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" - integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== - dependencies: - execa "^5.0.0" - jest-util "^29.7.0" - p-limit "^3.1.0" - -jest-circus@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" - integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== - dependencies: - "@jest/environment" "^29.7.0" - "@jest/expect" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - dedent "^1.0.0" - is-generator-fn "^2.0.0" - jest-each "^29.7.0" - jest-matcher-utils "^29.7.0" - jest-message-util "^29.7.0" - jest-runtime "^29.7.0" - jest-snapshot "^29.7.0" - jest-util "^29.7.0" - p-limit "^3.1.0" - pretty-format "^29.7.0" - pure-rand "^6.0.0" - slash "^3.0.0" - stack-utils "^2.0.3" - -jest-cli@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" - integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== - dependencies: - "@jest/core" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/types" "^29.6.3" - chalk "^4.0.0" - create-jest "^29.7.0" - exit "^0.1.2" - import-local "^3.0.2" - jest-config "^29.7.0" - jest-util "^29.7.0" - jest-validate "^29.7.0" - yargs "^17.3.1" - -jest-config@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" - integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== - dependencies: - "@babel/core" "^7.11.6" - "@jest/test-sequencer" "^29.7.0" - "@jest/types" "^29.6.3" - babel-jest "^29.7.0" - chalk "^4.0.0" - ci-info "^3.2.0" - deepmerge "^4.2.2" - glob "^7.1.3" - graceful-fs "^4.2.9" - jest-circus "^29.7.0" - jest-environment-node "^29.7.0" - jest-get-type "^29.6.3" - jest-regex-util "^29.6.3" - jest-resolve "^29.7.0" - jest-runner "^29.7.0" - jest-util "^29.7.0" - jest-validate "^29.7.0" - micromatch "^4.0.4" - parse-json "^5.2.0" - pretty-format "^29.7.0" - slash "^3.0.0" - strip-json-comments "^3.1.1" - -jest-diff@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" - integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== - dependencies: - chalk "^4.0.0" - diff-sequences "^29.6.3" - jest-get-type "^29.6.3" - pretty-format "^29.7.0" - -jest-docblock@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" - integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== - dependencies: - detect-newline "^3.0.0" - -jest-each@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" - integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== - dependencies: - "@jest/types" "^29.6.3" - chalk "^4.0.0" - jest-get-type "^29.6.3" - jest-util "^29.7.0" - pretty-format "^29.7.0" - -jest-environment-node@^29.2.1, jest-environment-node@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" - integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== - dependencies: - "@jest/environment" "^29.7.0" - "@jest/fake-timers" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - jest-mock "^29.7.0" - jest-util "^29.7.0" - -jest-get-type@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" - integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== - -jest-haste-map@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" - integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== - dependencies: - "@jest/types" "^29.6.3" - "@types/graceful-fs" "^4.1.3" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.9" - jest-regex-util "^29.6.3" - jest-util "^29.7.0" - jest-worker "^29.7.0" - micromatch "^4.0.4" - walker "^1.0.8" - optionalDependencies: - fsevents "^2.3.2" - -jest-leak-detector@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" - integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== - dependencies: - jest-get-type "^29.6.3" - pretty-format "^29.7.0" - -jest-matcher-utils@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" - integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== - dependencies: - chalk "^4.0.0" - jest-diff "^29.7.0" - jest-get-type "^29.6.3" - pretty-format "^29.7.0" - -jest-message-util@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" - integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== - dependencies: - "@babel/code-frame" "^7.12.13" - "@jest/types" "^29.6.3" - "@types/stack-utils" "^2.0.0" - chalk "^4.0.0" - graceful-fs "^4.2.9" - micromatch "^4.0.4" - pretty-format "^29.7.0" - slash "^3.0.0" - stack-utils "^2.0.3" - -jest-mock@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" - integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== - dependencies: - "@jest/types" "^29.6.3" - "@types/node" "*" - jest-util "^29.7.0" - -jest-pnp-resolver@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" - integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== - -jest-regex-util@^27.0.6: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95" - integrity sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg== - -jest-regex-util@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" - integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== - -jest-resolve-dependencies@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" - integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== - dependencies: - jest-regex-util "^29.6.3" - jest-snapshot "^29.7.0" - -jest-resolve@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" - integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== - dependencies: - chalk "^4.0.0" - graceful-fs "^4.2.9" - jest-haste-map "^29.7.0" - jest-pnp-resolver "^1.2.2" - jest-util "^29.7.0" - jest-validate "^29.7.0" - resolve "^1.20.0" - resolve.exports "^2.0.0" - slash "^3.0.0" - -jest-runner@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" - integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== - dependencies: - "@jest/console" "^29.7.0" - "@jest/environment" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - chalk "^4.0.0" - emittery "^0.13.1" - graceful-fs "^4.2.9" - jest-docblock "^29.7.0" - jest-environment-node "^29.7.0" - jest-haste-map "^29.7.0" - jest-leak-detector "^29.7.0" - jest-message-util "^29.7.0" - jest-resolve "^29.7.0" - jest-runtime "^29.7.0" - jest-util "^29.7.0" - jest-watcher "^29.7.0" - jest-worker "^29.7.0" - p-limit "^3.1.0" - source-map-support "0.5.13" - -jest-runtime@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" - integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== - dependencies: - "@jest/environment" "^29.7.0" - "@jest/fake-timers" "^29.7.0" - "@jest/globals" "^29.7.0" - "@jest/source-map" "^29.6.3" - "@jest/test-result" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - chalk "^4.0.0" - cjs-module-lexer "^1.0.0" - collect-v8-coverage "^1.0.0" - glob "^7.1.3" - graceful-fs "^4.2.9" - jest-haste-map "^29.7.0" - jest-message-util "^29.7.0" - jest-mock "^29.7.0" - jest-regex-util "^29.6.3" - jest-resolve "^29.7.0" - jest-snapshot "^29.7.0" - jest-util "^29.7.0" - slash "^3.0.0" - strip-bom "^4.0.0" - -jest-snapshot@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" - integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== - dependencies: - "@babel/core" "^7.11.6" - "@babel/generator" "^7.7.2" - "@babel/plugin-syntax-jsx" "^7.7.2" - "@babel/plugin-syntax-typescript" "^7.7.2" - "@babel/types" "^7.3.3" - "@jest/expect-utils" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" - babel-preset-current-node-syntax "^1.0.0" - chalk "^4.0.0" - expect "^29.7.0" - graceful-fs "^4.2.9" - jest-diff "^29.7.0" - jest-get-type "^29.6.3" - jest-matcher-utils "^29.7.0" - jest-message-util "^29.7.0" - jest-util "^29.7.0" - natural-compare "^1.4.0" - pretty-format "^29.7.0" - semver "^7.5.3" - -jest-util@^27.2.0: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9" - integrity sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw== - dependencies: - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - ci-info "^3.2.0" - graceful-fs "^4.2.9" - picomatch "^2.2.3" - -jest-util@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" - integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== - dependencies: - "@jest/types" "^29.6.3" - "@types/node" "*" - chalk "^4.0.0" - ci-info "^3.2.0" - graceful-fs "^4.2.9" - picomatch "^2.2.3" - -jest-validate@^29.2.1, jest-validate@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" - integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== - dependencies: - "@jest/types" "^29.6.3" - camelcase "^6.2.0" - chalk "^4.0.0" - jest-get-type "^29.6.3" - leven "^3.1.0" - pretty-format "^29.7.0" - -jest-watcher@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" - integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== - dependencies: - "@jest/test-result" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - emittery "^0.13.1" - jest-util "^29.7.0" - string-length "^4.0.1" - -jest-worker@^27.2.0: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" - integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^8.0.0" - -jest-worker@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" - integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== - dependencies: - "@types/node" "*" - jest-util "^29.7.0" - merge-stream "^2.0.0" - supports-color "^8.0.0" - -jest@^29.2.1: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" - integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== - dependencies: - "@jest/core" "^29.7.0" - "@jest/types" "^29.6.3" - import-local "^3.0.2" - jest-cli "^29.7.0" - -joi@^17.2.1: - version "17.6.0" - resolved "https://registry.yarnpkg.com/joi/-/joi-17.6.0.tgz#0bb54f2f006c09a96e75ce687957bd04290054b2" - integrity sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw== - dependencies: - "@hapi/hoek" "^9.0.0" - "@hapi/topo" "^5.0.0" - "@sideway/address" "^4.1.3" - "@sideway/formula" "^3.0.0" - "@sideway/pinpoint" "^2.0.0" - -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsc-android@^250231.0.0: - version "250231.0.0" - resolved "https://registry.yarnpkg.com/jsc-android/-/jsc-android-250231.0.0.tgz#91720f8df382a108872fa4b3f558f33ba5e95262" - integrity sha512-rS46PvsjYmdmuz1OAWXY/1kCYG7pnf1TBqeTiOJr1iDz7s5DLxxC9n/ZMknLDxzYzNVfI7R95MH10emSSG1Wuw== - -jsc-safe-url@^0.2.2: - version "0.2.4" - resolved "https://registry.yarnpkg.com/jsc-safe-url/-/jsc-safe-url-0.2.4.tgz#141c14fbb43791e88d5dc64e85a374575a83477a" - integrity sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q== - -jscodeshift@^0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.14.0.tgz#7542e6715d6d2e8bde0b4e883f0ccea358b46881" - integrity sha512-7eCC1knD7bLUPuSCwXsMZUH51O8jIcoVyKtI6P0XM0IVzlGjckPy3FIwQlorzbN0Sg79oK+RlohN32Mqf/lrYA== - dependencies: - "@babel/core" "^7.13.16" - "@babel/parser" "^7.13.16" - "@babel/plugin-proposal-class-properties" "^7.13.0" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.13.8" - "@babel/plugin-proposal-optional-chaining" "^7.13.12" - "@babel/plugin-transform-modules-commonjs" "^7.13.8" - "@babel/preset-flow" "^7.13.13" - "@babel/preset-typescript" "^7.13.0" - "@babel/register" "^7.13.16" - babel-core "^7.0.0-bridge.0" - chalk "^4.1.2" - flow-parser "0.*" - graceful-fs "^4.2.4" - micromatch "^4.0.4" - neo-async "^2.5.0" - node-dir "^0.1.17" - recast "^0.21.0" - temp "^0.8.4" - write-file-atomic "^2.3.0" - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -jsesc@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" - integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== - -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= - -json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - -json-parse-even-better-errors@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" - integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== - -json5@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" - integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== - -json5@^2.2.2, json5@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" - integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== - -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - -kind-of@^6.0.2: - version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== - -kleur@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" - integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== - -leven@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" - integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== - -lines-and-columns@^1.1.6: - version "1.2.4" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" - integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== - -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - -lodash.debounce@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= - -lodash.throttle@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" - integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= - -log-symbols@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" - integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== - dependencies: - chalk "^4.1.0" - is-unicode-supported "^0.1.0" - -logkitty@^0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/logkitty/-/logkitty-0.7.1.tgz#8e8d62f4085a826e8d38987722570234e33c6aa7" - integrity sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ== - dependencies: - ansi-fragments "^0.2.1" - dayjs "^1.8.15" - yargs "^15.1.0" - -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -make-dir@^2.0.0, make-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" - integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== - dependencies: - pify "^4.0.1" - semver "^5.6.0" - -make-dir@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - -makeerror@1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" - integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== - dependencies: - tmpl "1.0.5" - -memoize-one@^5.0.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" - integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - -metro-babel-transformer@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.76.9.tgz#659ba481d471b5f748c31a8f9397094b629f50ec" - integrity sha512-dAnAmBqRdTwTPVn4W4JrowPolxD1MDbuU97u3MqtWZgVRvDpmr+Cqnn5oSxLQk3Uc+Zy3wkqVrB/zXNRlLDSAQ== - dependencies: - "@babel/core" "^7.20.0" - hermes-parser "0.12.0" - nullthrows "^1.1.1" - -metro-cache-key@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-cache-key/-/metro-cache-key-0.76.9.tgz#6f17f821d6f306fa9028b7e79445eb18387d03d9" - integrity sha512-ugJuYBLngHVh1t2Jj+uP9pSCQl7enzVXkuh6+N3l0FETfqjgOaSHlcnIhMPn6yueGsjmkiIfxQU4fyFVXRtSTw== - -metro-cache@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-cache/-/metro-cache-0.76.9.tgz#64326d7a8b470c3886a5e97d5e2a20acab20bc5f" - integrity sha512-W6QFEU5AJG1gH4Ltv8S2IvhmEhSDYnbPafyj5fGR3YLysdykj+olKv9B0V+YQXtcLGyY5CqpXLYUx595GdiKzA== - dependencies: - metro-core "0.76.9" - rimraf "^3.0.2" - -metro-config@0.76.9, metro-config@^0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-config/-/metro-config-0.76.9.tgz#5e60aff9d8894c1ee6bbc5de23b7c8515a0b84a3" - integrity sha512-oYyJ16PY3rprsfoi80L+gDJhFJqsKI3Pob5LKQbJpvL+gGr8qfZe1eQzYp5Xxxk9DOHKBV1xD94NB8GdT/DA8Q== - dependencies: - connect "^3.6.5" - cosmiconfig "^5.0.5" - jest-validate "^29.2.1" - metro "0.76.9" - metro-cache "0.76.9" - metro-core "0.76.9" - metro-runtime "0.76.9" - -metro-core@0.76.9, metro-core@^0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-core/-/metro-core-0.76.9.tgz#5f55f0fbde41d28957e4f3bb187d32251403f00e" - integrity sha512-DSeEr43Wrd5Q7ySfRzYzDwfV89g2OZTQDf1s3exOcLjE5fb7awoLOkA2h46ZzN8NcmbbM0cuJy6hOwF073/yRQ== - dependencies: - lodash.throttle "^4.1.1" - metro-resolver "0.76.9" - -metro-file-map@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-file-map/-/metro-file-map-0.76.9.tgz#dd3d76ec23fc0ba8cb7b3a3b8075bb09e0b5d378" - integrity sha512-7vJd8kksMDTO/0fbf3081bTrlw8SLiploeDf+vkkf0OwlrtDUWPOikfebp+MpZB2S61kamKjCNRfRkgrbPfSwg== - dependencies: - anymatch "^3.0.3" - debug "^2.2.0" - fb-watchman "^2.0.0" - graceful-fs "^4.2.4" - invariant "^2.2.4" - jest-regex-util "^27.0.6" - jest-util "^27.2.0" - jest-worker "^27.2.0" - micromatch "^4.0.4" - node-abort-controller "^3.1.1" - nullthrows "^1.1.1" - walker "^1.0.7" - optionalDependencies: - fsevents "^2.3.2" - -metro-inspector-proxy@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-inspector-proxy/-/metro-inspector-proxy-0.76.9.tgz#0d333e64a7bc9d156d712265faa7b7ae88c775e8" - integrity sha512-idIiPkb8CYshc0WZmbzwmr4B1QwsQUbpDwBzHwxE1ni27FWKWhV9CD5p+qlXZHgfwJuMRfPN+tIaLSR8+vttYg== - dependencies: - connect "^3.6.5" - debug "^2.2.0" - node-fetch "^2.2.0" - ws "^7.5.1" - yargs "^17.6.2" - -metro-minify-terser@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-minify-terser/-/metro-minify-terser-0.76.9.tgz#3f6271da74dd57179852118443b62cc8dc578aab" - integrity sha512-ju2nUXTKvh96vHPoGZH/INhSvRRKM14CbGAJXQ98+g8K5z1v3luYJ/7+dFQB202eVzJdTB2QMtBjI1jUUpooCg== - dependencies: - terser "^5.15.0" - -metro-minify-uglify@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-minify-uglify/-/metro-minify-uglify-0.76.9.tgz#e88c30c27911c053e1ee20e12077f0f4cbb154f8" - integrity sha512-MXRrM3lFo62FPISlPfTqC6n9HTEI3RJjDU5SvpE7sJFfJKLx02xXQEltsL/wzvEqK+DhRQ5DEYACTwf5W4Z3yA== - dependencies: - uglify-es "^3.1.9" - -metro-react-native-babel-preset@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.76.9.tgz#15868142122af14313429d7572c15cf01c16f077" - integrity sha512-eCBtW/UkJPDr6HlMgFEGF+964DZsUEF9RGeJdZLKWE7d/0nY3ABZ9ZAGxzu9efQ35EWRox5bDMXUGaOwUe5ikQ== - dependencies: - "@babel/core" "^7.20.0" - "@babel/plugin-proposal-async-generator-functions" "^7.0.0" - "@babel/plugin-proposal-class-properties" "^7.18.0" - "@babel/plugin-proposal-export-default-from" "^7.0.0" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.0" - "@babel/plugin-proposal-numeric-separator" "^7.0.0" - "@babel/plugin-proposal-object-rest-spread" "^7.20.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" - "@babel/plugin-proposal-optional-chaining" "^7.20.0" - "@babel/plugin-syntax-dynamic-import" "^7.8.0" - "@babel/plugin-syntax-export-default-from" "^7.0.0" - "@babel/plugin-syntax-flow" "^7.18.0" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.0.0" - "@babel/plugin-syntax-optional-chaining" "^7.0.0" - "@babel/plugin-transform-arrow-functions" "^7.0.0" - "@babel/plugin-transform-async-to-generator" "^7.20.0" - "@babel/plugin-transform-block-scoping" "^7.0.0" - "@babel/plugin-transform-classes" "^7.0.0" - "@babel/plugin-transform-computed-properties" "^7.0.0" - "@babel/plugin-transform-destructuring" "^7.20.0" - "@babel/plugin-transform-flow-strip-types" "^7.20.0" - "@babel/plugin-transform-function-name" "^7.0.0" - "@babel/plugin-transform-literals" "^7.0.0" - "@babel/plugin-transform-modules-commonjs" "^7.0.0" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.0.0" - "@babel/plugin-transform-parameters" "^7.0.0" - "@babel/plugin-transform-react-display-name" "^7.0.0" - "@babel/plugin-transform-react-jsx" "^7.0.0" - "@babel/plugin-transform-react-jsx-self" "^7.0.0" - "@babel/plugin-transform-react-jsx-source" "^7.0.0" - "@babel/plugin-transform-runtime" "^7.0.0" - "@babel/plugin-transform-shorthand-properties" "^7.0.0" - "@babel/plugin-transform-spread" "^7.0.0" - "@babel/plugin-transform-sticky-regex" "^7.0.0" - "@babel/plugin-transform-typescript" "^7.5.0" - "@babel/plugin-transform-unicode-regex" "^7.0.0" - "@babel/template" "^7.0.0" - babel-plugin-transform-flow-enums "^0.0.2" - react-refresh "^0.4.0" - -metro-react-native-babel-transformer@^0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.76.9.tgz#464aab85669ed39f7a59f1fd993a05de9543b09e" - integrity sha512-xXzHcfngSIkbQj+U7i/anFkNL0q2QVarYSzr34CFkzKLa79Rp16B8ki7z9eVVqo9W3B4TBcTXl3BipgRoOoZSQ== - dependencies: - "@babel/core" "^7.20.0" - babel-preset-fbjs "^3.4.0" - hermes-parser "0.12.0" - metro-react-native-babel-preset "0.76.9" - nullthrows "^1.1.1" - -metro-resolver@0.76.9, metro-resolver@^0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-resolver/-/metro-resolver-0.76.9.tgz#79c244784b16ca56076bc1fc816d2ba74860e882" - integrity sha512-s86ipNRas9vNR5lChzzSheF7HoaQEmzxBLzwFA6/2YcGmUCowcoyPAfs1yPh4cjMw9F1T4KlMLaiwniGE7HCyw== - -metro-runtime@0.76.9, metro-runtime@^0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-runtime/-/metro-runtime-0.76.9.tgz#f8ebe150f8896ce1aef5d7f3a52844f8b4f721fb" - integrity sha512-/5vezDpGUtA0Fv6cJg0+i6wB+QeBbvLeaw9cTSG7L76liP0b91f8vOcYzGaUbHI8pznJCCTerxRzpQ8e3/NcDw== - dependencies: - "@babel/runtime" "^7.0.0" - react-refresh "^0.4.0" - -metro-source-map@0.76.9, metro-source-map@^0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.76.9.tgz#0f976ada836717f307427d3830aea52a2ca7ed5f" - integrity sha512-q5qsMlu8EFvsT46wUUh+ao+efDsicT30zmaPATNhq+PcTawDbDgnMuUD+FT0bvxxnisU2PWl91RdzKfNc2qPQA== - dependencies: - "@babel/traverse" "^7.20.0" - "@babel/types" "^7.20.0" - invariant "^2.2.4" - metro-symbolicate "0.76.9" - nullthrows "^1.1.1" - ob1 "0.76.9" - source-map "^0.5.6" - vlq "^1.0.0" - -metro-symbolicate@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-symbolicate/-/metro-symbolicate-0.76.9.tgz#f1627ef6f73bb0c4d48c55684d3c87866a0b0920" - integrity sha512-Yyq6Ukj/IeWnGST09kRt0sBK8TwzGZWoU7YAcQlh14+AREH454Olx4wbFTpkkhUkV05CzNCvUuXQ0efFxhA1bw== - dependencies: - invariant "^2.2.4" - metro-source-map "0.76.9" - nullthrows "^1.1.1" - source-map "^0.5.6" - through2 "^2.0.1" - vlq "^1.0.0" - -metro-transform-plugins@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-transform-plugins/-/metro-transform-plugins-0.76.9.tgz#73e34f2014d3df3c336a882b13e541bceb826d37" - integrity sha512-YEQeNlOCt92I7S9A3xbrfaDfwfgcxz9PpD/1eeop3c4cO3z3Q3otYuxw0WJ/rUIW8pZfOm5XCehd+1NRbWlAaw== - dependencies: - "@babel/core" "^7.20.0" - "@babel/generator" "^7.20.0" - "@babel/template" "^7.0.0" - "@babel/traverse" "^7.20.0" - nullthrows "^1.1.1" - -metro-transform-worker@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro-transform-worker/-/metro-transform-worker-0.76.9.tgz#281fad223f0447e1ff9cc44d6f7e33dfab9ab120" - integrity sha512-F69A0q0qFdJmP2Clqr6TpTSn4WTV9p5A28h5t9o+mB22ryXBZfUQ6BFBBW/6Wp2k/UtPH+oOsBfV9guiqm3d2Q== - dependencies: - "@babel/core" "^7.20.0" - "@babel/generator" "^7.20.0" - "@babel/parser" "^7.20.0" - "@babel/types" "^7.20.0" - babel-preset-fbjs "^3.4.0" - metro "0.76.9" - metro-babel-transformer "0.76.9" - metro-cache "0.76.9" - metro-cache-key "0.76.9" - metro-minify-terser "0.76.9" - metro-source-map "0.76.9" - metro-transform-plugins "0.76.9" - nullthrows "^1.1.1" - -metro@0.76.9, metro@^0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/metro/-/metro-0.76.9.tgz#605fddf1a54d27762ddba2f636420ae2408862df" - integrity sha512-gcjcfs0l5qIPg0lc5P7pj0x7vPJ97tan+OnEjiYLbKjR1D7Oa78CE93YUPyymUPH6q7VzlzMm1UjT35waEkZUw== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/core" "^7.20.0" - "@babel/generator" "^7.20.0" - "@babel/parser" "^7.20.0" - "@babel/template" "^7.0.0" - "@babel/traverse" "^7.20.0" - "@babel/types" "^7.20.0" - accepts "^1.3.7" - async "^3.2.2" - chalk "^4.0.0" - ci-info "^2.0.0" - connect "^3.6.5" - debug "^2.2.0" - denodeify "^1.2.1" - error-stack-parser "^2.0.6" - graceful-fs "^4.2.4" - hermes-parser "0.12.0" - image-size "^1.0.2" - invariant "^2.2.4" - jest-worker "^27.2.0" - jsc-safe-url "^0.2.2" - lodash.throttle "^4.1.1" - metro-babel-transformer "0.76.9" - metro-cache "0.76.9" - metro-cache-key "0.76.9" - metro-config "0.76.9" - metro-core "0.76.9" - metro-file-map "0.76.9" - metro-inspector-proxy "0.76.9" - metro-minify-uglify "0.76.9" - metro-react-native-babel-preset "0.76.9" - metro-resolver "0.76.9" - metro-runtime "0.76.9" - metro-source-map "0.76.9" - metro-symbolicate "0.76.9" - metro-transform-plugins "0.76.9" - metro-transform-worker "0.76.9" - mime-types "^2.1.27" - node-fetch "^2.2.0" - nullthrows "^1.1.1" - rimraf "^3.0.2" - serialize-error "^2.1.0" - source-map "^0.5.6" - strip-ansi "^6.0.0" - throat "^5.0.0" - ws "^7.5.1" - yargs "^17.6.2" - -micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== - dependencies: - braces "^3.0.2" - picomatch "^2.3.1" - -mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -mime-types@^2.1.27, mime-types@~2.1.34: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -mime@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - -mime@^2.4.1: - version "2.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" - integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" - integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== - -mkdirp@^0.5.1: - version "0.5.6" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" - integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== - dependencies: - minimist "^1.2.6" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -negotiator@0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" - integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== - -neo-async@^2.5.0: - version "2.6.2" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" - integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== - -nocache@^3.0.1: - version "3.0.4" - resolved "https://registry.yarnpkg.com/nocache/-/nocache-3.0.4.tgz#5b37a56ec6e09fc7d401dceaed2eab40c8bfdf79" - integrity sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw== - -node-abort-controller@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.1.1.tgz#a94377e964a9a37ac3976d848cb5c765833b8548" - integrity sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ== - -node-dir@^0.1.17: - version "0.1.17" - resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5" - integrity sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU= - dependencies: - minimatch "^3.0.2" - -node-fetch@^2.2.0, node-fetch@^2.6.0: - version "2.6.7" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== - dependencies: - whatwg-url "^5.0.0" - -node-int64@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= - -node-releases@^2.0.19: - version "2.0.19" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" - integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== - -node-releases@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.5.tgz#280ed5bc3eba0d96ce44897d8aee478bfb3d9666" - integrity sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q== - -node-stream-zip@^1.9.1: - version "1.15.0" - resolved "https://registry.yarnpkg.com/node-stream-zip/-/node-stream-zip-1.15.0.tgz#158adb88ed8004c6c49a396b50a6a5de3bca33ea" - integrity sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw== - -normalize-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - -nullthrows@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1" - integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw== - -ob1@0.76.9: - version "0.76.9" - resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.76.9.tgz#a493e4b83a0fb39200de639804b5d06eed5599dc" - integrity sha512-g0I/OLnSxf6OrN3QjSew3bTDJCdbZoWxnh8adh1z36alwCuGF1dgDeRA25bTYSakrG5WULSaWJPOdgnf1O/oQw== - -object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object.assign@^4.1.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" - integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - has-symbols "^1.0.1" - object-keys "^1.1.1" - -on-finished@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" - integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== - dependencies: - ee-first "1.1.1" - -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= - dependencies: - ee-first "1.1.1" - -on-headers@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" - integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - -onetime@^5.1.0, onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -"onnxruntime-common@file:../common": - version "1.21.0" - -open@^6.2.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/open/-/open-6.4.0.tgz#5c13e96d0dc894686164f18965ecfe889ecfc8a9" - integrity sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg== - dependencies: - is-wsl "^1.1.0" - -ora@^5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" - integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== - dependencies: - bl "^4.1.0" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-spinners "^2.5.0" - is-interactive "^1.0.0" - is-unicode-supported "^0.1.0" - log-symbols "^4.1.0" - strip-ansi "^6.0.0" - wcwidth "^1.0.1" - -p-limit@^2.0.0, p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-limit@^3.0.2, p-limit@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - -p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - -parse-json@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" - integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== - dependencies: - "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-even-better-errors "^2.3.0" - lines-and-columns "^1.1.6" - -parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - -path-key@^3.0.0, path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== - -picocolors@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" - integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== - -picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -pify@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" - integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - -pirates@^4.0.4, pirates@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" - integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== - -pkg-dir@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" - integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== - dependencies: - find-up "^3.0.0" - -pkg-dir@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - -plist@^3.0.5: - version "3.0.6" - resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.6.tgz#7cfb68a856a7834bca6dbfe3218eb9c7740145d3" - integrity sha512-WiIVYyrp8TD4w8yCvyeIr+lkmrGRd5u0VbRnU+tP/aRLxP/YadJUYOMZJ/6hIa3oUyVCsycXvtNRgd5XBJIbiA== - dependencies: - base64-js "^1.5.1" - xmlbuilder "^15.1.1" - -pod-install@^0.1.36: - version "0.1.36" - resolved "https://registry.yarnpkg.com/pod-install/-/pod-install-0.1.36.tgz#8090f57f76b42acf24c4325711bfa5730613fcab" - integrity sha512-r+f2SAqtM4K81Wv4OAhedbfCtBZhPz+1c1CVkQ1vT33PGAhM5A6GpaJ0pfQVgfZ0tUwagWxlDQ3eOprNyIFO6w== - -prettier@^2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.2.tgz#e26d71a18a74c3d0f0597f55f01fb6c06c206032" - integrity sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew== - -pretty-format@^26.5.2, pretty-format@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" - integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== - dependencies: - "@jest/types" "^26.6.2" - ansi-regex "^5.0.0" - ansi-styles "^4.0.0" - react-is "^17.0.1" - -pretty-format@^29.0.0, pretty-format@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" - integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== - dependencies: - "@jest/schemas" "^29.6.3" - ansi-styles "^5.0.0" - react-is "^18.0.0" - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - -promise@^8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/promise/-/promise-8.3.0.tgz#8cb333d1edeb61ef23869fbb8a4ea0279ab60e0a" - integrity sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg== - dependencies: - asap "~2.0.6" - -prompts@^2.0.1, prompts@^2.4.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" - integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== - dependencies: - kleur "^3.0.3" - sisteransi "^1.0.5" - -prop-types@^15.8.1: - version "15.8.1" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" - integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.13.1" - -pure-rand@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" - integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== - -queue@6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/queue/-/queue-6.0.2.tgz#b91525283e2315c7553d2efa18d83e76432fed65" - integrity sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA== - dependencies: - inherits "~2.0.3" - -range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -react-devtools-core@^4.27.2: - version "4.28.5" - resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-4.28.5.tgz#c8442b91f068cdf0c899c543907f7f27d79c2508" - integrity sha512-cq/o30z9W2Wb4rzBefjv5fBalHU0rJGZCHAkf/RHSBWSSYwh8PlQTqqOJmgIIbBtpj27T6FIPXeomIjZtCNVqA== - dependencies: - shell-quote "^1.6.1" - ws "^7" - -"react-is@^16.12.0 || ^17.0.0 || ^18.0.0": - version "18.2.0" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" - integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== - -react-is@^16.13.1: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - -react-is@^17.0.1: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" - integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== - -react-is@^18.0.0: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" - integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== - -react-native@^0.72.17: - version "0.72.17" - resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.72.17.tgz#54d6de38adf6e56fdde1a6b83ef9b138abae7384" - integrity sha512-k3dNe0XqoYCGGWTenbupWSj+ljW3GIfmYS5P4s3if4j0csx2YbenKgH1aJNWLp+UP7ONwfId6G+uBoUJfyMxXg== - dependencies: - "@jest/create-cache-key-function" "^29.2.1" - "@react-native-community/cli" "^11.4.1" - "@react-native-community/cli-platform-android" "^11.4.1" - "@react-native-community/cli-platform-ios" "^11.4.1" - "@react-native/assets-registry" "^0.72.0" - "@react-native/codegen" "^0.72.8" - "@react-native/gradle-plugin" "^0.72.11" - "@react-native/js-polyfills" "^0.72.1" - "@react-native/normalize-colors" "^0.72.0" - "@react-native/virtualized-lists" "^0.72.8" - abort-controller "^3.0.0" - anser "^1.4.9" - ansi-regex "^5.0.0" - base64-js "^1.1.2" - deprecated-react-native-prop-types "^4.2.3" - event-target-shim "^5.0.1" - flow-enums-runtime "^0.0.5" - invariant "^2.2.4" - jest-environment-node "^29.2.1" - jsc-android "^250231.0.0" - memoize-one "^5.0.0" - metro-runtime "^0.76.9" - metro-source-map "^0.76.9" - mkdirp "^0.5.1" - nullthrows "^1.1.1" - pretty-format "^26.5.2" - promise "^8.3.0" - react-devtools-core "^4.27.2" - react-refresh "^0.4.0" - react-shallow-renderer "^16.15.0" - regenerator-runtime "^0.13.2" - scheduler "0.24.0-canary-efb381bbf-20230505" - stacktrace-parser "^0.1.10" - use-sync-external-store "^1.0.0" - whatwg-fetch "^3.0.0" - ws "^6.2.2" - yargs "^17.6.2" - -react-refresh@^0.4.0: - version "0.4.3" - resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.4.3.tgz#966f1750c191672e76e16c2efa569150cc73ab53" - integrity sha512-Hwln1VNuGl/6bVwnd0Xdn1e84gT/8T9aYNL+HAKDArLCS7LWjwr7StE30IEYbIkx0Vi3vs+coQxe+SQDbGbbpA== - -react-shallow-renderer@^16.15.0: - version "16.15.0" - resolved "https://registry.yarnpkg.com/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz#48fb2cf9b23d23cde96708fe5273a7d3446f4457" - integrity sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA== - dependencies: - object-assign "^4.1.1" - react-is "^16.12.0 || ^17.0.0 || ^18.0.0" - -react@^18.2.0: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" - integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== - dependencies: - loose-envify "^1.1.0" - -readable-stream@^3.4.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readable-stream@~2.3.6: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readline@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/readline/-/readline-1.3.0.tgz#c580d77ef2cfc8752b132498060dc9793a7ac01c" - integrity sha1-xYDXfvLPyHUrEySYBg3JeTp6wBw= - -recast@^0.21.0: - version "0.21.5" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.21.5.tgz#e8cd22bb51bcd6130e54f87955d33a2b2e57b495" - integrity sha512-hjMmLaUXAm1hIuTqOdeYObMslq/q+Xff6QE3Y2P+uoHAg2nmVlLBps2hzh1UJDdMtDTMXOFewK6ky51JQIeECg== - dependencies: - ast-types "0.15.2" - esprima "~4.0.0" - source-map "~0.6.1" - tslib "^2.0.1" - -regenerate-unicode-properties@^10.0.1: - version "10.0.1" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz#7f442732aa7934a3740c779bb9b3340dccc1fb56" - integrity sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw== - dependencies: - regenerate "^1.4.2" - -regenerate@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" - integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== - -regenerator-runtime@^0.13.2, regenerator-runtime@^0.13.4: - version "0.13.9" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" - integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== - -regexpu-core@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.0.1.tgz#c531122a7840de743dcf9c83e923b5560323ced3" - integrity sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw== - dependencies: - regenerate "^1.4.2" - regenerate-unicode-properties "^10.0.1" - regjsgen "^0.6.0" - regjsparser "^0.8.2" - unicode-match-property-ecmascript "^2.0.0" - unicode-match-property-value-ecmascript "^2.0.0" - -regexpu-core@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.1.0.tgz#2f8504c3fd0ebe11215783a41541e21c79942c6d" - integrity sha512-bb6hk+xWd2PEOkj5It46A16zFMs2mv86Iwpdu94la4S3sJ7C973h2dHpYKwIBGaWSO7cIRJ+UX0IeMaWcO4qwA== - dependencies: - regenerate "^1.4.2" - regenerate-unicode-properties "^10.0.1" - regjsgen "^0.6.0" - regjsparser "^0.8.2" - unicode-match-property-ecmascript "^2.0.0" - unicode-match-property-value-ecmascript "^2.0.0" - -regjsgen@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.6.0.tgz#83414c5354afd7d6627b16af5f10f41c4e71808d" - integrity sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA== - -regjsparser@^0.8.2: - version "0.8.4" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.8.4.tgz#8a14285ffcc5de78c5b95d62bbf413b6bc132d5f" - integrity sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA== - dependencies: - jsesc "~0.5.0" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - -require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== - -resolve-cwd@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" - integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== - dependencies: - resolve-from "^5.0.0" - -resolve-from@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - integrity sha1-six699nWiBvItuZTM17rywoYh0g= - -resolve-from@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" - integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== - -resolve.exports@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.3.tgz#41955e6f1b4013b7586f873749a635dea07ebe3f" - integrity sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A== - -resolve@^1.14.2, resolve@^1.20.0: - version "1.22.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" - integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== - dependencies: - is-core-module "^2.8.1" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -rimraf@~2.6.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -sax@>=0.6.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - -scheduler@0.24.0-canary-efb381bbf-20230505: - version "0.24.0-canary-efb381bbf-20230505" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.24.0-canary-efb381bbf-20230505.tgz#5dddc60e29f91cd7f8b983d7ce4a99c2202d178f" - integrity sha512-ABvovCDe/k9IluqSh4/ISoq8tIJnW8euVAWYt5j/bg6dRnqwQwiGO1F/V4AyK96NGF/FB04FhOUDuWj8IKfABA== - dependencies: - loose-envify "^1.1.0" - -semver@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" - integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== - -semver@^5.6.0: - version "5.7.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" - integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== - -semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0, semver@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@^7.5.2, semver@^7.5.4: - version "7.6.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== - -semver@^7.5.3: - version "7.5.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" - integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== - dependencies: - lru-cache "^6.0.0" - -send@0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" - integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== - dependencies: - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "2.0.0" - mime "1.6.0" - ms "2.1.3" - on-finished "2.4.1" - range-parser "~1.2.1" - statuses "2.0.1" - -serialize-error@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-2.1.0.tgz#50b679d5635cdf84667bdc8e59af4e5b81d5f60a" - integrity sha1-ULZ51WNc34Rme9yOWa9OW4HV9go= - -serve-static@^1.13.1: - version "1.15.0" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" - integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.18.0" - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - -setprototypeof@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" - integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== - -shallow-clone@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" - integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== - dependencies: - kind-of "^6.0.2" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -shell-quote@^1.6.1, shell-quote@^1.7.3: - version "1.7.3" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" - integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== - -signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -simple-plist@^1.1.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/simple-plist/-/simple-plist-1.3.1.tgz#16e1d8f62c6c9b691b8383127663d834112fb017" - integrity sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw== - dependencies: - bplist-creator "0.1.0" - bplist-parser "0.3.1" - plist "^3.0.5" - -sisteransi@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" - integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -slice-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - -source-map-support@0.5.13: - version "0.5.13" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" - integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-support@^0.5.16, source-map-support@~0.5.20: - version "0.5.21" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.5.6: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -source-map@^0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -stack-utils@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" - integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== - dependencies: - escape-string-regexp "^2.0.0" - -stackframe@^1.1.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.2.1.tgz#1033a3473ee67f08e2f2fc8eba6aef4f845124e1" - integrity sha512-h88QkzREN/hy8eRdyNhhsO7RSJ5oyTqxxmmn0dzBIMUclZsjpfmrsg81vp8mjjAs2vAZ72nyWxRUwSwmh0e4xg== - -stacktrace-parser@^0.1.10: - version "0.1.10" - resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a" - integrity sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg== - dependencies: - type-fest "^0.7.1" - -statuses@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" - integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== - -statuses@~1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= - -stream-buffers@2.2.x: - version "2.2.0" - resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-2.2.0.tgz#91d5f5130d1cef96dcfa7f726945188741d09ee4" - integrity sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg== - -string-length@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" - integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== - dependencies: - char-regex "^1.0.2" - strip-ansi "^6.0.0" - -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^5.0.0, strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-bom@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" - integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== - -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - -strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -strnum@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db" - integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA== - -sudo-prompt@^9.0.0: - version "9.2.1" - resolved "https://registry.yarnpkg.com/sudo-prompt/-/sudo-prompt-9.2.1.tgz#77efb84309c9ca489527a4e749f287e6bdd52afd" - integrity sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw== - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-color@^8.0.0: - version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - -temp@^0.8.4: - version "0.8.4" - resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.4.tgz#8c97a33a4770072e0a05f919396c7665a7dd59f2" - integrity sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg== - dependencies: - rimraf "~2.6.2" - -terser@^5.15.0: - version "5.37.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.37.0.tgz#38aa66d1cfc43d0638fab54e43ff8a4f72a21ba3" - integrity sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA== - dependencies: - "@jridgewell/source-map" "^0.3.3" - acorn "^8.8.2" - commander "^2.20.0" - source-map-support "~0.5.20" - -test-exclude@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" - integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== - dependencies: - "@istanbuljs/schema" "^0.1.2" - glob "^7.1.4" - minimatch "^3.0.4" - -throat@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" - integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== - -through2@^2.0.1: - version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" - integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - -tmpl@1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" - integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -toidentifier@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" - integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== - -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= - -tslib@^2.0.1: - version "2.4.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" - integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== - -type-detect@4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== - -type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - -type-fest@^0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" - integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== - -uglify-es@^3.1.9: - version "3.3.9" - resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" - integrity sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ== - dependencies: - commander "~2.13.0" - source-map "~0.6.1" - -unicode-canonical-property-names-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" - integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== - -unicode-match-property-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" - integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== - dependencies: - unicode-canonical-property-names-ecmascript "^2.0.0" - unicode-property-aliases-ecmascript "^2.0.0" - -unicode-match-property-value-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" - integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== - -unicode-property-aliases-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" - integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== - -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - -unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= - -update-browserslist-db@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz#97e9c96ab0ae7bcac08e9ae5151d26e6bc6b5580" - integrity sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg== - dependencies: - escalade "^3.2.0" - picocolors "^1.1.1" - -use-sync-external-store@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" - integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== - -util-deprecate@^1.0.1, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= - -uuid@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" - integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== - -v8-to-istanbul@^9.0.1: - version "9.3.0" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" - integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== - dependencies: - "@jridgewell/trace-mapping" "^0.3.12" - "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^2.0.0" - -vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= - -vlq@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/vlq/-/vlq-1.0.1.tgz#c003f6e7c0b4c1edd623fd6ee50bbc0d6a1de468" - integrity sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w== - -walker@^1.0.7, walker@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" - integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== - dependencies: - makeerror "1.0.12" - -wcwidth@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" - integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= - dependencies: - defaults "^1.0.3" - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= - -whatwg-fetch@^3.0.0: - version "3.6.2" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c" - integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA== - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -wrap-ansi@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" - integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -write-file-atomic@^2.3.0: - version "2.4.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" - integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ== - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - signal-exit "^3.0.2" - -write-file-atomic@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" - integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== - dependencies: - imurmurhash "^0.1.4" - signal-exit "^3.0.7" - -ws@^6.2.2: - version "6.2.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.3.tgz#ccc96e4add5fd6fedbc491903075c85c5a11d9ee" - integrity sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA== - dependencies: - async-limiter "~1.0.0" - -ws@^7, ws@^7.5.1: - version "7.5.7" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.7.tgz#9e0ac77ee50af70d58326ecff7e85eb3fa375e67" - integrity sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A== - -xcode@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/xcode/-/xcode-3.0.1.tgz#3efb62aac641ab2c702458f9a0302696146aa53c" - integrity sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA== - dependencies: - simple-plist "^1.1.0" - uuid "^7.0.3" - -xml2js@0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.6.0.tgz#07afc447a97d2bd6507a1f76eeadddb09f7a8282" - integrity sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w== - dependencies: - sax ">=0.6.0" - xmlbuilder "~11.0.0" - -xmlbuilder@^14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-14.0.0.tgz#876b5aec4f05ffd5feb97b0a871c855d16fbeb8c" - integrity sha512-ts+B2rSe4fIckR6iquDjsKbQFK2NlUk6iG5nf14mDEyldgoc2nEKZ3jZWMPTxGQwVgToSjt6VGIho1H8/fNFTg== - -xmlbuilder@^15.1.1: - version "15.1.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5" - integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg== - -xmlbuilder@~11.0.0: - version "11.0.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" - integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== - -xtend@~4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - -y18n@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" - integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== - -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yaml@^2.2.1: - version "2.7.0" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.7.0.tgz#aef9bb617a64c937a9a748803786ad8d3ffe1e98" - integrity sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA== - -yargs-parser@^18.1.2: - version "18.1.3" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" - integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs-parser@^21.1.1: - version "21.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" - integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== - -yargs@^15.1.0: - version "15.4.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" - integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== - dependencies: - cliui "^6.0.0" - decamelize "^1.2.0" - find-up "^4.1.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^4.2.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^18.1.2" - -yargs@^17.3.1, yargs@^17.6.2: - version "17.7.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" - integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== - dependencies: - cliui "^8.0.1" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.3" - y18n "^5.0.5" - yargs-parser "^21.1.1" - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/js/web/lib/backend-wasm.ts b/js/web/lib/backend-wasm.ts index 72b51d565896a..fe8bfaa188ea9 100644 --- a/js/web/lib/backend-wasm.ts +++ b/js/web/lib/backend-wasm.ts @@ -17,12 +17,13 @@ export const initializeFlags = (): void => { env.wasm.initTimeout = 0; } - if (env.wasm.simd === false) { + const simd = env.wasm.simd; + if (typeof simd !== 'boolean' && simd !== undefined && simd !== 'fixed' && simd !== 'relaxed') { // eslint-disable-next-line no-console console.warn( - 'Deprecated property "env.wasm.simd" is set to false. ' + - 'non-SIMD build is no longer provided, and this setting will be ignored.', + `Property "env.wasm.simd" is set to unknown value "${simd}". Reset it to \`false\` and ignore SIMD feature checking.`, ); + env.wasm.simd = false; } if (typeof env.wasm.proxy !== 'boolean') { @@ -88,7 +89,7 @@ export class OnnxruntimeWebAssemblyBackend implements Backend { ): Promise { const handler = new OnnxruntimeWebAssemblySessionHandler(); await handler.loadModel(pathOrBuffer, options); - return Promise.resolve(handler); + return handler; } } diff --git a/js/web/lib/build-def.d.ts b/js/web/lib/build-def.d.ts index 59f64a3179605..83a52ebaefe05 100644 --- a/js/web/lib/build-def.d.ts +++ b/js/web/lib/build-def.d.ts @@ -40,6 +40,13 @@ interface BuildDefinitions { */ readonly ENABLE_BUNDLE_WASM_JS: boolean; + /** + * defines whether to use WebGPU EP instead of JSEP for WebGPU backend. + * + * This flag requires the corresponding WebAssembly artifact to be built with `--use_webgpu` flag. + */ + readonly USE_WEBGPU_EP: boolean; + // #endregion // #region Build definitions for ESM diff --git a/js/web/lib/onnxjs/session-handler-inference.ts b/js/web/lib/onnxjs/session-handler-inference.ts index c1c2576971840..f13ee7a56c78a 100644 --- a/js/web/lib/onnxjs/session-handler-inference.ts +++ b/js/web/lib/onnxjs/session-handler-inference.ts @@ -12,6 +12,14 @@ export class OnnxjsSessionHandler implements InferenceSessionHandler { this.outputNames = this.session.outputNames; } + get inputMetadata(): readonly InferenceSession.ValueMetadata[] { + throw new Error('Getting model metadata is not supported in webgl backend.'); + } + + get outputMetadata(): readonly InferenceSession.ValueMetadata[] { + throw new Error('Getting model metadata is not supported in webgl backend.'); + } + async dispose(): Promise {} inputNames: readonly string[]; outputNames: readonly string[]; diff --git a/js/web/lib/version.ts b/js/web/lib/version.ts index 475dfe0d4888b..8ec54c0bd22dc 100644 --- a/js/web/lib/version.ts +++ b/js/web/lib/version.ts @@ -4,4 +4,4 @@ // This file is generated by /js/scripts/update-version.ts // Do not modify file content manually. -export const version = '1.21.0'; +export const version = '1.22.0'; diff --git a/js/web/lib/wasm/jsep/backend-webgpu.ts b/js/web/lib/wasm/jsep/backend-webgpu.ts index a0010df4643a4..413e89111740e 100644 --- a/js/web/lib/wasm/jsep/backend-webgpu.ts +++ b/js/web/lib/wasm/jsep/backend-webgpu.ts @@ -13,7 +13,6 @@ import { ProgramManager } from './webgpu/program-manager'; import { AdapterInfo, ComputeContext, - DeviceInfo, GpuArchitecture, GpuData, GpuVendor, @@ -135,26 +134,6 @@ class AdapterInfoImpl implements AdapterInfo { } } -class DeviceInfoImpl implements DeviceInfo { - readonly subgroupsSupported: boolean; - readonly subgroupsF16Supported: boolean; - readonly subgroupSizeRange?: readonly [number, number]; - - constructor(device: GPUDevice) { - this.subgroupsSupported = device.features.has('subgroups' as GPUFeatureName); - this.subgroupsF16Supported = device.features.has('subgroups' as GPUFeatureName); - // Currently subgroups feature is still experimental and size attributes are not in the WebGPU IDL, so we have to - // workaround the IDL type checks. - // TODO: clean this after subgroups feature is settled in IDL. - const deviceSubgroupsLimits = device.limits as { minSubgroupSize?: number; maxSubgroupSize?: number }; - if (!this.subgroupsSupported || !deviceSubgroupsLimits.minSubgroupSize || !deviceSubgroupsLimits.maxSubgroupSize) { - this.subgroupSizeRange = undefined; - } else { - this.subgroupSizeRange = [deviceSubgroupsLimits.minSubgroupSize, deviceSubgroupsLimits.maxSubgroupSize]; - } - } -} - /** * this class is designed to store status and being used as a singleton for JSEP. It will be passed to jsepInit() as * the first parameter so that it is stored for future use. @@ -162,7 +141,6 @@ class DeviceInfoImpl implements DeviceInfo { export class WebGpuBackend { adapterInfo: AdapterInfoImpl; device: GPUDevice; - deviceInfo: DeviceInfoImpl; /** * an instance of GpuDataManager to manage a GpuDataId -> GpuBuffer mapping */ @@ -274,13 +252,9 @@ export class WebGpuBackend { } requireFeatureIfAvailable('shader-f16'); // Try subgroups - if (requireFeatureIfAvailable('subgroups' as GPUFeatureName)) { - // If subgroups feature is available, also try subgroups-f16 - requireFeatureIfAvailable('subgroups-f16' as GPUFeatureName); - } + requireFeatureIfAvailable('subgroups' as GPUFeatureName); this.device = await adapter.requestDevice(deviceDescriptor); - this.deviceInfo = new DeviceInfoImpl(this.device); this.adapterInfo = new AdapterInfoImpl(adapter.info || (await adapter.requestAdapterInfo())); this.gpuDataManager = createGpuDataManager(this); this.programManager = new ProgramManager(this); diff --git a/js/web/lib/wasm/jsep/backend-webnn.ts b/js/web/lib/wasm/jsep/backend-webnn.ts index 2b9a9208e2e53..c2a855bedca22 100644 --- a/js/web/lib/wasm/jsep/backend-webnn.ts +++ b/js/web/lib/wasm/jsep/backend-webnn.ts @@ -12,7 +12,7 @@ import { DataType } from '../wasm-common'; import { getInstance } from '../wasm-factory'; import { createView } from './tensor-view'; -import { TensorId, createTensorManager } from './webnn/tensor-manager'; +import { TensorId, createTensorManager, convertInt64ToInt32 } from './webnn/tensor-manager'; import { configureLogger, LOG_DEBUG } from './log'; /* @@ -288,6 +288,7 @@ export class WebNNBackend { builder: MLGraphBuilder, desc: MLOperandDescriptor, mountedFiles: Map | undefined, + shouldConvertInt64ToInt32 = false, ): MLOperand { // If available, "Module.MountedFiles" is a Map for all preloaded files. if (!mountedFiles) { @@ -314,7 +315,8 @@ export class WebNNBackend { bufferView = new Float32Array(buffer); break; case 'float16': - bufferView = new Uint16Array(buffer); + bufferView = + typeof Float16Array !== 'undefined' && Float16Array.from ? new Float16Array(buffer) : new Uint16Array(buffer); break; case 'int32': bufferView = new Int32Array(buffer); @@ -323,7 +325,13 @@ export class WebNNBackend { bufferView = new Uint32Array(buffer); break; case 'int64': - bufferView = new BigInt64Array(buffer); + if (shouldConvertInt64ToInt32) { + // Int64 is not supported by current context, use int32 instead. + bufferView = convertInt64ToInt32(new Uint8Array(buffer), false) as Int32Array; + desc.dataType = 'int32'; + } else { + bufferView = new BigInt64Array(buffer); + } break; case 'uint64': bufferView = new BigUint64Array(buffer); @@ -340,7 +348,13 @@ export class WebNNBackend { throw new Error(`Unsupported data type: ${desc.dataType} in creating WebNN Constant from external data.`); } - LOG_DEBUG('verbose', () => `[WebNN] registerMLConstant {dataType: ${desc.dataType}, shape: ${desc.shape}}}`); + LOG_DEBUG( + 'verbose', + () => + `[WebNN] registerMLConstant {dataType: ${desc.dataType}, shape: ${desc.shape}}} ${ + shouldConvertInt64ToInt32 ? '(Note: it was int64 data type and registered to int32 as workaround)' : '' + }`, + ); return builder.constant(desc, bufferView); } @@ -357,6 +371,11 @@ export class WebNNBackend { return inputNames.includes(inputName); } + public isInt64Supported(sessionId: number): boolean { + const context = this.mlContextBySessionId.get(sessionId); + return !!context?.opSupportLimits().input.dataTypes.includes('int64'); + } + public flush(): void { // Unlike the WebGPU backend, the WebNN backend does not need to flush any pending operations. } diff --git a/js/web/lib/wasm/jsep/init.ts b/js/web/lib/wasm/jsep/init.ts index b4071eae51c8f..8ab6b054bf8a7 100644 --- a/js/web/lib/wasm/jsep/init.ts +++ b/js/web/lib/wasm/jsep/init.ts @@ -1,23 +1,17 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { Env } from 'onnxruntime-common'; +import type { Env } from 'onnxruntime-common'; import { calculateTensorSizeInBytes, DataType } from '../wasm-common'; import type { OrtWasmModule } from '../wasm-types'; -import { WebGpuBackend } from './backend-webgpu'; +import type { WebGpuBackend } from './backend-webgpu'; import { LOG_DEBUG } from './log'; -import { TensorView } from './tensor-view'; +import type { TensorView } from './tensor-view'; import { ShapeUtil } from './util'; -import { - AdapterInfo, - ComputeContext, - ComputeContextInputsOutputsMapping, - DeviceInfo, - ProgramInfo, -} from './webgpu/types'; +import type { AdapterInfo, ComputeContext, ComputeContextInputsOutputsMapping, ProgramInfo } from './webgpu/types'; import { WebNNBackend } from './backend-webnn'; /* eslint-disable no-bitwise */ @@ -76,7 +70,6 @@ class TensorViewImpl implements TensorView { class ComputeContextImpl implements ComputeContext { readonly adapterInfo: AdapterInfo; - readonly deviceInfo: DeviceInfo; readonly opKernelContext: number; readonly inputs: readonly TensorView[]; readonly outputCount: number; @@ -94,7 +87,6 @@ class ComputeContextImpl implements ComputeContext { contextDataOffset: number, ) { this.adapterInfo = backend.adapterInfo; - this.deviceInfo = backend.deviceInfo; // extract context data const ptrSize = module.PTR_SIZE; @@ -205,79 +197,83 @@ export const init = async ( } if (name === 'webgpu') { - const backend = new WebGpuBackend(); - await backend.initialize(env, gpuAdapter!); + if (!BUILD_DEFS.USE_WEBGPU_EP) { + // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires + const webGpuBackendImpl = require('./backend-webgpu').WebGpuBackend; + const backend = new webGpuBackendImpl(); + await backend.initialize(env, gpuAdapter!); - jsepInit('webgpu', [ - // backend - backend, + jsepInit('webgpu', [ + // backend + backend, + + // jsepAlloc() + (size: number) => backend.alloc(Number(size)), - // jsepAlloc() - (size: number) => backend.alloc(Number(size)), + // jsepFree() + (ptr: number) => backend.free(ptr), - // jsepFree() - (ptr: number) => backend.free(ptr), + // jsepCopy(src, dst, size, isSourceGpu) + (src: number, dst: number, size: number, isSourceGpu = false) => { + if (isSourceGpu) { + LOG_DEBUG( + 'verbose', + () => `[WebGPU] jsepCopyGpuToGpu: src=${Number(src)}, dst=${Number(dst)}, size=${Number(size)}`, + ); + backend.memcpy(Number(src), Number(dst)); + } else { + LOG_DEBUG( + 'verbose', + () => + `[WebGPU] jsepCopyCpuToGpu: dataOffset=${Number(src)}, gpuDataId=${Number(dst)}, size=${Number(size)}`, + ); + const data = module.HEAPU8.subarray(Number(src >>> 0), Number(src >>> 0) + Number(size)); + backend.upload(Number(dst), data); + } + }, - // jsepCopy(src, dst, size, isSourceGpu) - (src: number, dst: number, size: number, isSourceGpu = false) => { - if (isSourceGpu) { + // jsepCopyAsync(src, dst, size) + async (gpuDataId: number, dataOffset: number, size: number): Promise => { LOG_DEBUG( 'verbose', - () => `[WebGPU] jsepCopyGpuToGpu: src=${Number(src)}, dst=${Number(dst)}, size=${Number(size)}`, + () => `[WebGPU] jsepCopyGpuToCpu: gpuDataId=${gpuDataId}, dataOffset=${dataOffset}, size=${size}`, ); - backend.memcpy(Number(src), Number(dst)); - } else { - LOG_DEBUG( - 'verbose', - () => - `[WebGPU] jsepCopyCpuToGpu: dataOffset=${Number(src)}, gpuDataId=${Number(dst)}, size=${Number(size)}`, - ); - const data = module.HEAPU8.subarray(Number(src >>> 0), Number(src >>> 0) + Number(size)); - backend.upload(Number(dst), data); - } - }, - // jsepCopyAsync(src, dst, size) - async (gpuDataId: number, dataOffset: number, size: number): Promise => { - LOG_DEBUG( - 'verbose', - () => `[WebGPU] jsepCopyGpuToCpu: gpuDataId=${gpuDataId}, dataOffset=${dataOffset}, size=${size}`, - ); - - await backend.download(Number(gpuDataId), () => - module.HEAPU8.subarray(Number(dataOffset) >>> 0, Number(dataOffset + size) >>> 0), - ); - }, + await backend.download(Number(gpuDataId), () => + module.HEAPU8.subarray(Number(dataOffset) >>> 0, Number(dataOffset + size) >>> 0), + ); + }, - // jsepCreateKernel - (kernelType: string, kernelId: number, attribute: unknown) => - backend.createKernel( - kernelType, - Number(kernelId), - attribute, - module.UTF8ToString(module._JsepGetNodeName!(Number(kernelId))), - ), + // jsepCreateKernel + (kernelType: string, kernelId: number, attribute: unknown) => + backend.createKernel( + kernelType, + Number(kernelId), + attribute, + module.UTF8ToString(module._JsepGetNodeName!(Number(kernelId))), + ), - // jsepReleaseKernel - (kernel: number) => backend.releaseKernel(kernel), + // jsepReleaseKernel + (kernel: number) => backend.releaseKernel(kernel), - // jsepRun - (kernel: number, contextDataOffset: number, sessionHandle: number, errors: Array>) => { - LOG_DEBUG( - 'verbose', - () => - `[WebGPU] jsepRun: sessionHandle=${sessionHandle}, kernel=${kernel}, contextDataOffset=${contextDataOffset}`, - ); - const context = new ComputeContextImpl(module, backend, Number(contextDataOffset)); - return backend.computeKernel(Number(kernel), context, errors); - }, - // jsepCaptureBegin - () => backend.captureBegin(), - // jsepCaptureEnd - () => backend.captureEnd(), - // jsepReplay - () => backend.replay(), - ]); + // jsepRun + (kernel: number, contextDataOffset: number, sessionHandle: number, errors: Array>) => { + LOG_DEBUG( + 'verbose', + () => + `[WebGPU] jsepRun: sessionHandle=${sessionHandle}, kernel=${kernel}, contextDataOffset=${contextDataOffset}`, + ); + const context = new ComputeContextImpl(module, backend, Number(contextDataOffset)); + return backend.computeKernel(Number(kernel), context, errors); + }, + // jsepCaptureBegin + () => backend.captureBegin(), + // jsepCaptureEnd + () => backend.captureEnd(), + // jsepReplay + () => backend.replay(), + ]); + } } else { const backend = new WebNNBackend(env); jsepInit('webnn', [ diff --git a/js/web/lib/wasm/jsep/webgpu/ops/3rd-party/conv_backprop_webgpu.ts b/js/web/lib/wasm/jsep/webgpu/ops/3rd-party/conv_backprop_webgpu.ts index ad1de42106d6d..50620cea33863 100644 --- a/js/web/lib/wasm/jsep/webgpu/ops/3rd-party/conv_backprop_webgpu.ts +++ b/js/web/lib/wasm/jsep/webgpu/ops/3rd-party/conv_backprop_webgpu.ts @@ -46,6 +46,11 @@ export const createConvTranspose2DProgramInfo = ( const inputChannelsPerGroup = wShape[2] / group; const outputChannelsPerGroup = wShape[3]; const aComponents = isChannelsLast ? getMaxComponents(inputChannelsPerGroup) : 1; + const packInputAs4 = isChannelsLast && outputChannelsPerGroup === 1 && inputChannelsPerGroup >= 4; + const inputChannelsPerGroupInt = packInputAs4 + ? Math.floor(inputChannelsPerGroup / 4) * 4 + : Math.floor(inputChannelsPerGroup / aComponents) * aComponents; + const inputChannelsRemainder = inputChannelsPerGroup - inputChannelsPerGroupInt; const components = isChannelsLast ? getMaxComponents(outputChannelsPerGroup) : 1; const bComponents = isChannelsLast ? (outputChannelsPerGroup === 1 ? aComponents : components) : 1; const outputSize = ShapeUtil.size(outputShape) / components; @@ -78,6 +83,7 @@ export const createConvTranspose2DProgramInfo = ( { type: DataType.uint32, data: dilations }, { type: DataType.uint32, data: effectiveFilterDims }, { type: DataType.int32, data: pads }, + { type: DataType.uint32, data: inputChannelsPerGroupInt }, { type: DataType.uint32, data: inputChannelsPerGroup }, { type: DataType.uint32, data: outputChannelsPerGroup }, ...createTensorShapeVariables(inputs[0].dims, inputs[1].dims), @@ -96,6 +102,7 @@ export const createConvTranspose2DProgramInfo = ( { name: 'dilations', type: 'u32', length: filterDims.length }, { name: 'effective_filter_dims', type: 'u32', length: effectiveFilterDims.length }, { name: 'pads', type: 'i32', length: pads.length }, + { name: 'input_channels_per_group_int', type: 'u32' }, { name: 'input_channels_per_group', type: 'u32' }, { name: 'output_channels_per_group', type: 'u32' }, ]; @@ -114,16 +121,40 @@ export const createConvTranspose2DProgramInfo = ( const calculateResult = (): string => { let calcStr = ''; - if (aComponents === 1) { - calcStr += ` - let w_offset = ${w.indicesToOffset(`${w.type.indices}(u32(wRPerm), u32(wCPerm), inputChannel, wOutChannel)`)}; - let wValue = ${w.getByOffset(`w_offset / ${bComponents}`)}; - dotProd = dotProd + xValue * wValue;`; + if (packInputAs4) { + if (aComponents === 4) { + calcStr += ` + let xValue = ${dy.getByOffset('x_offset')}; + let wValue = ${w.getByOffset('w_offset')}; + dotProd = dotProd + dot(xValue, wValue); + x_offset += 1u; + w_offset += 1u;`; + } else if (aComponents === 2) { + calcStr += ` + dotProd = dotProd + dot(vec4<${dataType}>(${dy.getByOffset('x_offset')}, ${dy.getByOffset('x_offset + 1u')}), vec4<${dataType}>(${w.getByOffset('w_offset')}, ${w.getByOffset('w_offset + 1u')})); + x_offset += 2u; + w_offset += 2u;`; + } else if (aComponents === 1) { + calcStr += ` + dotProd = dotProd + dot(vec4<${dataType}>(${dy.getByOffset('x_offset')}, ${dy.getByOffset('x_offset + 1u')}, ${dy.getByOffset('x_offset + 2u')}, ${dy.getByOffset('x_offset + 3u')}), vec4<${dataType}>(${w.getByOffset('w_offset')}, ${w.getByOffset('w_offset + 1u')}, ${w.getByOffset('w_offset + 2u')}, ${w.getByOffset('w_offset + 3u')})); + x_offset += 4u; + w_offset += 4u;`; + } } else { - if (outputChannelsPerGroup === 1) { + calcStr += ` + let xValue = ${ + isChannelsLast + ? dy.getByOffset( + `${dy.indicesToOffset(`${dy.type.indices}(batch, idyR, idyC, inputChannel)`)} / ${aComponents}`, + ) + : dy.get('batch', 'inputChannel', 'idyR', 'idyC') + }; + `; + if (aComponents === 1) { calcStr += ` - let wValue = ${w.getByOffset(`${w.indicesToOffset(`${w.type.indices}(u32(wRPerm), u32(wCPerm), inputChannel, wOutChannel)`)} / ${bComponents}`)}; - dotProd = dotProd + dot(xValue, wValue);`; + let w_offset = ${w.indicesToOffset(`${w.type.indices}(u32(wRPerm), u32(wCPerm), inputChannel, wOutChannel)`)}; + let wValue = ${w.getByOffset(`w_offset / ${bComponents}`)}; + dotProd = dotProd + xValue * wValue;`; } else { for (let c = 0; c < aComponents; c++) { calcStr += ` @@ -134,6 +165,32 @@ export const createConvTranspose2DProgramInfo = ( } return calcStr; }; + const calculateRemainder = (): string => { + if (inputChannelsRemainder === 0) { + return ''; + } + if (!packInputAs4) { + throw new Error(`packInputAs4 ${packInputAs4} is not true.`); + } + let calcStr = ''; + if (aComponents === 1) { + calcStr += 'dotProd = dotProd'; + for (let i = 0; i < inputChannelsRemainder; i++) { + calcStr += ` + + ${dy.getByOffset(`x_offset + ${i}`)} * ${w.getByOffset(`w_offset + ${i}`)}`; + } + calcStr += ';'; + } else if (aComponents === 2) { + if (inputChannelsRemainder !== 2) { + throw new Error(`Invalid inputChannelsRemainder ${inputChannelsRemainder}.`); + } + calcStr += ` + let xValue = ${dy.getByOffset('x_offset')}; + let wValue = ${w.getByOffset('w_offset')}; + dotProd = dotProd + dot(xValue, wValue);`; + } + return calcStr; + }; const codeSnippet = ` let outputIndices = ${output.offsetToIndices(`global_idx * ${components}`)}; let batch = ${output.indicesGet('outputIndices', 0)}; @@ -169,7 +226,6 @@ export const createConvTranspose2DProgramInfo = ( // Minimum wC >= 0 that satisfies (dyCCorner + wC) % (uniforms.strides.y) == 0 wC = u32(((dyCCorner + i32(uniforms.strides.y) - 1) / i32(uniforms.strides.y)) * i32(uniforms.strides.y) - dyCCorner); } - for (; wC < uniforms.effective_filter_dims.y; wC = wC + 1) { if (wC % uniforms.dilations.y != 0) { continue; @@ -182,17 +238,19 @@ export const createConvTranspose2DProgramInfo = ( } let idyC: u32 = u32(dyC); var inputChannel = groupId * uniforms.input_channels_per_group; - for (var d2: u32 = 0; d2 < uniforms.input_channels_per_group; d2 = d2 + ${aComponents}) { - let xValue = ${ - isChannelsLast - ? dy.getByOffset( - `${dy.indicesToOffset(`${dy.type.indices}(batch, idyR, idyC, inputChannel)`)} / ${aComponents}`, - ) - : dy.get('batch', 'inputChannel', 'idyR', 'idyC') - }; + ${ + packInputAs4 + ? ` + var x_offset = ${dy.indicesToOffset(`${dy.type.indices}(batch, idyR, idyC, inputChannel)`)} / ${aComponents}; + var w_offset = ${w.indicesToOffset(`${w.type.indices}(wRPerm, wCPerm, inputChannel, wOutChannel)`)} / ${bComponents}; + ` + : '' + } + for (var d2: u32 = 0; d2 < uniforms.input_channels_per_group_int; d2 = d2 + ${packInputAs4 ? 4 : aComponents}) { ${calculateResult()} - inputChannel = inputChannel + ${aComponents}; + inputChannel = inputChannel + ${packInputAs4 ? 4 : aComponents}; } + ${calculateRemainder()} wC = wC + uniforms.strides.y - 1; } wR = wR + uniforms.strides[0] - 1; @@ -211,7 +269,7 @@ export const createConvTranspose2DProgramInfo = ( return { name: 'ConvTranspose2D', shaderCache: { - hint: `${attributes.cacheKey};${aComponents}${bComponents}${components}${outputChannelsPerGroup === 1}`, + hint: `${attributes.cacheKey};${aComponents}${bComponents}${components}${packInputAs4}${inputChannelsRemainder}`, inputDependencies, }, getRunData: () => ({ diff --git a/js/web/lib/wasm/jsep/webgpu/ops/attention.ts b/js/web/lib/wasm/jsep/webgpu/ops/attention.ts index 6a78c8ae3b190..6a8dffb73fa08 100644 --- a/js/web/lib/wasm/jsep/webgpu/ops/attention.ts +++ b/js/web/lib/wasm/jsep/webgpu/ops/attention.ts @@ -433,7 +433,7 @@ const createInPlaceSoftmaxProgramInfo = ( getShaderSource, getRunData: () => ({ outputs: [], - dispatchGroup: { x: Math.ceil(totalSequenceLength / WG), y: sequenceLength, z: batchSize * numHeads }, + dispatchGroup: { x: 1, y: sequenceLength, z: batchSize * numHeads }, programUniforms, }), }; diff --git a/js/web/lib/wasm/jsep/webgpu/ops/grid-sample.ts b/js/web/lib/wasm/jsep/webgpu/ops/grid-sample.ts index 50c71472434ad..16c3af871b4e6 100644 --- a/js/web/lib/wasm/jsep/webgpu/ops/grid-sample.ts +++ b/js/web/lib/wasm/jsep/webgpu/ops/grid-sample.ts @@ -126,6 +126,8 @@ const pixelAtGrid = (input: IndicesHelper, dataType: string, attributes: GridSam if (r >= 0 && r < H && c >=0 && c < W) { indices[${idxH}] = u32(r); indices[${idxW}] = u32(c); + } else { + return ${dataType}(0); } `; case 'border': diff --git a/js/web/lib/wasm/jsep/webgpu/ops/group-query-attention.ts b/js/web/lib/wasm/jsep/webgpu/ops/group-query-attention.ts index 85b8c4ca5a274..32b3c54f734dc 100644 --- a/js/web/lib/wasm/jsep/webgpu/ops/group-query-attention.ts +++ b/js/web/lib/wasm/jsep/webgpu/ops/group-query-attention.ts @@ -3,12 +3,15 @@ import { TensorView } from '../../tensor-view'; import { createAttributeWithCacheKey } from '../attribute-with-cache-key'; -import { ComputeContext } from '../types'; +import { ComputeContext, ProgramInputTensorInfoDependency, ProgramUniform } from '../types'; +import { DataType } from '../../../wasm-common'; import { applyAttention, AttentionMaskType, AttentionParameters, AttentionQkvFormat } from './attention'; import { maybeTransposeToBNSHAndAddBias } from './multihead-attention'; import { createSplitProgramInfo, SplitAttributes } from './split'; import { createTransposeProgramInfo, TransposeAttributes } from './transpose'; +import { RotaryEmbeddingAttributes, createRotaryEmbeddingProgramInfo } from './rotary-embedding'; +import { inputVariable, outputVariable, ShaderHelper, UniformsArrayType } from './common'; export interface GroupQueryAttentionAttributes { numHeads: number; kvNumHeads: number; @@ -24,9 +27,6 @@ export const validateInputs = ( inputs: readonly TensorView[], attributes: GroupQueryAttentionAttributes, ): AttentionParameters => { - if (attributes.doRotary) { - throw new Error('GroupQuerryAttention do_rotary attribute is not supported'); - } if (attributes.doRotary && inputs.length <= 7) { throw new Error('cos_cache and sin_cache inputs are required if do_rotary is specified'); } @@ -35,6 +35,9 @@ export const validateInputs = ( const value = inputs[2]; const pastKey = inputs[3]; const pastValue = inputs[4]; + if (attributes.doRotary !== 0 && inputs.length <= 7) { + throw new Error('cos_cast and sin_cache are expected if do_rotary attribute is non-zero'); + } if (attributes.localWindowSize !== -1) { throw new Error('Local attention is not supported'); } @@ -238,6 +241,77 @@ const maybeTransposeToBNSH = (context: ComputeContext, input: TensorView, params return reshapedInput; }; +const generatePositionIdsProgramInfo = ( + batchSize: number, + sequenceLength: number, + seqLens: TensorView, + totalSeqLen: TensorView, +) => { + const outputDataType = DataType.int64; + const inputDependencies: ProgramInputTensorInfoDependency[] = ['type', 'type']; + const outputShape = [batchSize * sequenceLength]; + const outputSize = batchSize * sequenceLength; + const programUniforms: ProgramUniform[] = [ + { type: DataType.uint32, data: outputSize }, + { type: DataType.uint32, data: sequenceLength }, + { type: DataType.uint32, data: batchSize }, + ]; + const getShaderSource = (shaderHelper: ShaderHelper) => { + const seqLensInputHelper = inputVariable('seq_lens', seqLens.dataType, seqLens.dims); + const totalSeqLenInputHelper = inputVariable('total_seq_lens', totalSeqLen.dataType, totalSeqLen.dims); + const positionIdsHelper = outputVariable('pos_ids', outputDataType, outputShape); + + const uniforms: UniformsArrayType = [ + { name: 'output_size', type: 'u32' }, + { name: 'sequence_length', type: 'u32' }, + { name: 'batch_size', type: 'u32' }, + ]; + + return ` + ${shaderHelper.registerUniforms(uniforms).declareVariables(seqLensInputHelper, totalSeqLenInputHelper, positionIdsHelper)} + ${shaderHelper.mainStart()} + ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes('uniforms.output_size')} + let total_sequence_length = u32(${totalSeqLenInputHelper.getByOffset('0')}); + let is_subsequent_prompt = uniforms.sequence_length > 1 && uniforms.sequence_length != total_sequence_length; + let is_first_prompt = !is_subsequent_prompt && uniforms.sequence_length == total_sequence_length; + let batch_idx = global_idx / uniforms.sequence_length; + let sequence_idx = i32(global_idx % uniforms.sequence_length); + var pos_id: i32 = 0; + let seqlen = ${seqLensInputHelper.getByOffset('batch_idx')}; + let total_seqlen = seqlen + 1; + if (is_first_prompt) { + if (sequence_idx < total_seqlen) { + pos_id = sequence_idx; + } else { + pos_id = 1; + } + ${positionIdsHelper.setByOffset('global_idx', 'pos_id')} + } else if (is_subsequent_prompt) { + let past_seqlen = total_seqlen - i32(uniforms.sequence_length); + if (past_seqlen + sequence_idx < total_seqlen) { + pos_id = past_seqlen + sequence_idx; + } else { + pos_id = 1; + } + ${positionIdsHelper.setByOffset('global_idx', 'pos_id')} + } else if (global_idx < uniforms.batch_size) { + ${positionIdsHelper.setByOffset('global_idx', 'seqlen')} + }; + } + `; + }; + return { + name: 'GeneratePositionIds', + shaderCache: { hint: `${batchSize};${sequenceLength}`, inputDependencies }, + getRunData: () => ({ + outputs: [{ dims: outputShape, dataType: outputDataType }], + dispatchGroup: { x: Math.ceil(outputSize / 64 /* workgroup size */) }, + programUniforms, + }), + getShaderSource, + }; +}; + export const groupQueryAttention = (context: ComputeContext, attributes: GroupQueryAttentionAttributes): void => { const params = validateInputs(context.inputs, attributes); if (context.inputs[0].dims.length === 5) { @@ -268,22 +342,57 @@ export const groupQueryAttention = (context: ComputeContext, attributes: GroupQu !k && !v ? context.compute(createSplitProgramInfo([q], splitAttributes), { inputs: [q], outputs: [-1, -1, -1] }) : [q, k!, v!]; - + let qRotary: TensorView | undefined; + let kRotary: TensorView | undefined; + if (attributes.doRotary) { + const posIds = context.compute( + generatePositionIdsProgramInfo(params.batchSize, params.sequenceLength, seqLens!, totalSequenceLengthInput!), + { inputs: [seqLens!, totalSequenceLengthInput!], outputs: [-1] }, + )[0]; + const cosCache = context.inputs[7]; + const sinCache = context.inputs[8]; + const qRotaryEmbeddingAttributes: RotaryEmbeddingAttributes = createAttributeWithCacheKey({ + interleaved: attributes.rotaryInterleaved !== 0, + numHeads: params.numHeads, + rotaryEmbeddingDim: 0, + scale: attributes.scale, + }); + const inputs = [query, posIds, cosCache, sinCache]; + const outputs = [-1]; + qRotary = context.compute(createRotaryEmbeddingProgramInfo(inputs, qRotaryEmbeddingAttributes), { + inputs, + outputs, + })[0]; + inputs.splice(0, 1, key); + const kRotaryEmbeddingAttributes: RotaryEmbeddingAttributes = createAttributeWithCacheKey({ + interleaved: attributes.rotaryInterleaved !== 0, + numHeads: params.kvNumHeads!, + rotaryEmbeddingDim: 0, + scale: attributes.scale, + }); + kRotary = context.compute(createRotaryEmbeddingProgramInfo(inputs, kRotaryEmbeddingAttributes), { + inputs, + outputs, + })[0]; + } const Q = maybeTransposeToBNSHAndAddBias( context, params.batchSize, params.numHeads, params.sequenceLength, params.headSize, - query, + attributes.doRotary ? qRotary! : query, undefined, 0, ); + const K = maybeTransposeToBNSH(context, attributes.doRotary ? kRotary! : key, params); + const V = maybeTransposeToBNSH(context, value, params); + applyAttention( context, Q, - maybeTransposeToBNSH(context, key, params), - maybeTransposeToBNSH(context, value, params), + K, + V, undefined, undefined, pastKey, diff --git a/js/web/lib/wasm/jsep/webgpu/ops/rotary-embedding.ts b/js/web/lib/wasm/jsep/webgpu/ops/rotary-embedding.ts index 8eb7a10ac91fa..fe2567e71d49a 100644 --- a/js/web/lib/wasm/jsep/webgpu/ops/rotary-embedding.ts +++ b/js/web/lib/wasm/jsep/webgpu/ops/rotary-embedding.ts @@ -75,7 +75,7 @@ const validateInputs = (inputs: readonly TensorView[], attributes: RotaryEmbeddi } }; -const createRotaryEmbeddingProgramInfo = ( +export const createRotaryEmbeddingProgramInfo = ( inputs: readonly TensorView[], attributes: RotaryEmbeddingAttributes, ): ProgramInfo => { diff --git a/js/web/lib/wasm/jsep/webgpu/ops/scatter-nd.ts b/js/web/lib/wasm/jsep/webgpu/ops/scatter-nd.ts index 7fd0c2ef42aff..ec1d23e4887d5 100644 --- a/js/web/lib/wasm/jsep/webgpu/ops/scatter-nd.ts +++ b/js/web/lib/wasm/jsep/webgpu/ops/scatter-nd.ts @@ -78,6 +78,36 @@ const atomicReductionSnippet = (reduction: string, ptr: string, v: string, type: } }; +const calcDataOffsetSnippet = (dataRank: number, parallel: boolean) => + `${ + dataRank === 1 + ? ` + let element_count_dim = uniforms.output_strides; + let dim_value = uniforms.output_shape;` + : ` + let element_count_dim = uniforms.output_strides[${parallel ? 'i - indices_start' : 'i'}]; + let dim_value = uniforms.output_shape[${parallel ? 'i - indices_start' : 'i'} + uniforms.last_index_dimension];` + } + + if (index >= 0) { + if (index >= i32(dim_value)) { + index = i32(dim_value - 1); + } + } else { + if (index < -i32(dim_value)) { + index = 0; + } else { + index += i32(dim_value); + } + } + data_offset += u32((u32(index) * element_count_dim));`; + +const updateElementsSnippet = (attributes: ScatterNDAttributes, outputTypeValue: ReductionType, parallel: boolean) => + `for (var i = 0u; i < uniforms.num_updates_elements; i++) { + let value = updates[uniforms.num_updates_elements * ${parallel ? 'global_idx' : 'idx'} + i]; + ${atomicReductionSnippet(attributes.reduction, 'output[data_offset + i]', 'value', outputTypeValue)} + }`; + const createScatterNDProgramInfo = (inputs: readonly TensorView[], attributes: ScatterNDAttributes): ProgramInfo => { const inputShape = inputs[0].dims; const indicesShape = inputs[1].dims; @@ -87,6 +117,7 @@ const createScatterNDProgramInfo = (inputs: readonly TensorView[], attributes: S const outputSize = Math.ceil(ShapeUtil.size(indicesShape) / components); const lastIndexDimension = indicesShape[indicesShape.length - 1]; const numUpdatesElements = ShapeUtil.sizeFromDimension(inputShape, lastIndexDimension); + const numIndicesElements = ShapeUtil.sizeFromDimension(indicesShape, 0) / lastIndexDimension; const programUniforms: ProgramUniform[] = [ { type: DataType.uint32, data: outputSize }, @@ -113,9 +144,8 @@ const createScatterNDProgramInfo = (inputs: readonly TensorView[], attributes: S ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes('uniforms.output_size')} var hasDuplicates = false; if (${attributes.reduction === 'none'}) { - let n = ${ShapeUtil.size(indicesShape)}; - for (var i = 0; i < n; i = i + 1) { - for (var j = i + 1; j < n; j = j + 1) { + for (var i = 0; i < ${numIndicesElements}; i = i + 1) { + for (var j = i + 1; j < ${numIndicesElements}; j = j + 1) { var index_i = i32(indices[i].x); var index_j = i32(indices[j].x); if (index_i == index_j) { @@ -129,51 +159,31 @@ const createScatterNDProgramInfo = (inputs: readonly TensorView[], attributes: S } } - var data_offset = 0u; - var indices_start = uniforms.last_index_dimension * global_idx; if (${attributes.reduction === 'none'} && hasDuplicates) { if (global_idx != 0u) { return; } - indices_start = 0u; - } - let indices_end = indices_start + uniforms.last_index_dimension; - for (var i = indices_start; i < indices_end; i++) { - var index = i32(indices[i].x); - ${ - inputs[0].dims.length === 1 - ? ` - let element_count_dim = uniforms.output_strides; - let dim_value = uniforms.output_shape;` - : ` - let element_count_dim = uniforms.output_strides[i - indices_start]; - let dim_value = uniforms.output_shape[i - indices_start + uniforms.last_index_dimension];` - } - if (index >= 0) { - if (index >= i32(dim_value)) { - index = i32(dim_value - 1); - } - } else { - if (index < -i32(dim_value)) { - index = 0; - } else { - index += i32(dim_value); + // Process each index-update pair individually when duplicates exist + for (var idx = 0u; idx < ${numIndicesElements}u; idx++) { + var data_offset = 0u; + for (var i = 0u; i < uniforms.last_index_dimension; i++) { + var index = i32(indices[idx * uniforms.last_index_dimension + i].x); + ${calcDataOffsetSnippet(inputShape.length, false)} } + ${updateElementsSnippet(attributes, output.type.value as ReductionType, false)} } - data_offset += u32((u32(index) * element_count_dim)); + return; } - for (var i = 0u; i < uniforms.num_updates_elements; i++) { - let value = updates[uniforms.num_updates_elements * global_idx + i]; - ${atomicReductionSnippet( - attributes.reduction, - 'output[data_offset + i]', - 'value', - output.type.value as ReductionType, - )} + var data_offset = 0u; + var indices_start = uniforms.last_index_dimension * global_idx; + var indices_end = indices_start + uniforms.last_index_dimension; + for (var i = indices_start; i < indices_end; i++) { + var index = i32(indices[i].x); + ${calcDataOffsetSnippet(inputShape.length, true)} } - - }`; + ${updateElementsSnippet(attributes, output.type.value as ReductionType, true)} + }`; }; return { name: 'ScatterND', diff --git a/js/web/lib/wasm/jsep/webgpu/program-manager.ts b/js/web/lib/wasm/jsep/webgpu/program-manager.ts index 2c5180c5db3ee..18d505f57655a 100644 --- a/js/web/lib/wasm/jsep/webgpu/program-manager.ts +++ b/js/web/lib/wasm/jsep/webgpu/program-manager.ts @@ -99,7 +99,6 @@ export class ProgramManager { const extensionsInfo: Array<{ feature: GPUFeatureName; extension: string }> = [ { feature: 'shader-f16', extension: 'f16' }, { feature: 'subgroups' as GPUFeatureName, extension: 'subgroups' }, - { feature: 'subgroups-f16' as GPUFeatureName, extension: 'subgroups_f16' }, ]; extensionsInfo.forEach((info) => { if (device.features.has(info.feature)) { diff --git a/js/web/lib/wasm/jsep/webgpu/types.ts b/js/web/lib/wasm/jsep/webgpu/types.ts index 9321ac170d036..f3cfc6cb98cae 100644 --- a/js/web/lib/wasm/jsep/webgpu/types.ts +++ b/js/web/lib/wasm/jsep/webgpu/types.ts @@ -21,11 +21,6 @@ export interface AdapterInfo { isArchitecture: (architecture: GpuArchitecture) => boolean; isVendor: (vendor: GpuVendor) => boolean; } -export interface DeviceInfo { - readonly subgroupsSupported: boolean; - readonly subgroupsF16Supported: boolean; - readonly subgroupSizeRange?: readonly [number, number]; -} export interface GpuData { type: GpuDataType; @@ -165,11 +160,6 @@ export interface ComputeContext { */ readonly adapterInfo: AdapterInfo; - /** - * gpu device info - */ - readonly deviceInfo: DeviceInfo; - /** * stores the pointer to OpKernelContext */ diff --git a/js/web/lib/wasm/jsep/webnn/tensor-manager.ts b/js/web/lib/wasm/jsep/webnn/tensor-manager.ts index ebdd5069aa089..24d68576c176c 100644 --- a/js/web/lib/wasm/jsep/webnn/tensor-manager.ts +++ b/js/web/lib/wasm/jsep/webnn/tensor-manager.ts @@ -9,6 +9,53 @@ import { LOG_DEBUG } from '../log'; // https://github.com/webmachinelearning/webnn/issues/677 /// +// Convert BigInt64Array buffer data to Int32Array buffer data. +export const convertInt64ToInt32 = (data: Uint8Array, returnUint8 = true): Uint8Array | Int32Array => { + // Make sure it is a multiple of 8 bytes (BigInt64Array). + if (data.byteLength % 8 !== 0) { + throw new Error('Invalid Uint8Array length - must be a multiple of 8 (BigInt).'); + } + + // Convert Uint8Array to BigInt64Array. + const numElements = data.byteLength / 8; + const bigInt64Array = new BigInt64Array(data.buffer, data.byteOffset, numElements); + + // Convert BigInt64Array to Int32Array (same number of elements). + const int32Array = new Int32Array(numElements); + + for (let i = 0; i < numElements; i++) { + const value = bigInt64Array[i]; + + // Check for overflow. + if (value > 2147483647n || value < -2147483648n) { + throw new Error(`Overflow occurred when converting BigInt to Int32 at index ${i}: ${value}`); + } + + int32Array[i] = Number(value); + } + + // Return based on the requested format. + return returnUint8 ? new Uint8Array(int32Array.buffer) : int32Array; +}; + +// Convert Int32Array buffer data to BigInt64Array buffer data. +const convertInt32ToInt64 = (data: Uint8Array, returnUint8 = true): Uint8Array | BigInt64Array => { + // Make sure it is a multiple of 4 bytes (Int32Array). + if (data.byteLength % 4 !== 0) { + throw new Error('Invalid Uint8Array length - must be a multiple of 4 (Int32).'); + } + + // Convert Uint8Array to Int32Array. + const numElements = data.byteLength / 4; + const int32Array = new Int32Array(data.buffer, data.byteOffset, numElements); + + // Convert Int32Array to BigInt64Array (same number of elements). + const bigInt64Array = BigInt64Array.from(int32Array, BigInt); + + // Return based on the requested format. + return returnUint8 ? new Uint8Array(bigInt64Array.buffer) : bigInt64Array; +}; + export type TensorId = number; /** @@ -88,6 +135,9 @@ const calculateByteLength = (dataType: MLOperandDataType, shape: readonly number class TensorWrapper { // The id of the last session that used this tensor. public sessionId: number; + // This flag is used to indicate whether we should convert data from int64 to int32. + public shouldConvertInt64toInt32 = false; + public isInt64ToInt32Converted = false; private mlContext: MLContext; private mlTensor: MLTensor; @@ -100,12 +150,15 @@ class TensorWrapper { tensor: MLTensor; dataType: MLOperandDataType; shape: readonly number[]; + shouldConvertInt64toInt32?: boolean; }) { - this.sessionId = descriptor.sessionId; - this.mlContext = descriptor.context; - this.mlTensor = descriptor.tensor; - this.dataType = descriptor.dataType; - this.tensorShape = descriptor.shape; + const { sessionId, context, tensor, dataType, shape, shouldConvertInt64toInt32 = false } = descriptor; + this.sessionId = sessionId; + this.mlContext = context; + this.mlTensor = tensor; + this.dataType = dataType; + this.tensorShape = shape; + this.shouldConvertInt64toInt32 = shouldConvertInt64toInt32; } public get tensor(): MLTensor { @@ -133,13 +186,33 @@ class TensorWrapper { this.mlContext.writeTensor(this.mlTensor, data); } - public async read(): Promise; - public async read(dstBuffer: ArrayBufferView | ArrayBuffer): Promise; - async read(dstBuffer?: ArrayBufferView | ArrayBuffer): Promise { - if (dstBuffer) { - return this.mlContext.readTensor(this.mlTensor, dstBuffer); + public async read(shouldConvertInt32ToInt64?: boolean): Promise; + public async read( + shouldConvertInt32ToInt64?: boolean, + dstBuffer?: ArrayBufferView | ArrayBuffer, + ): Promise; + public async read( + shouldConvertInt32ToInt64?: boolean, + dstBuffer?: ArrayBufferView | ArrayBuffer, + ): Promise { + if (shouldConvertInt32ToInt64) { + // This was an int64 data as saved as int32 as workaround, we need to read it as int64. + const data = await this.mlContext.readTensor(this.mlTensor); + const int64Data = convertInt32ToInt64(new Uint8Array(data)) as Uint8Array; + + if (dstBuffer) { + const targetBuffer = + dstBuffer instanceof ArrayBuffer + ? new Uint8Array(dstBuffer) + : new Uint8Array(dstBuffer.buffer, dstBuffer.byteOffset, dstBuffer.byteLength); + targetBuffer.set(int64Data); + return undefined; + } else { + return int64Data.buffer; + } + } else { + return dstBuffer ? this.mlContext.readTensor(this.mlTensor, dstBuffer) : this.mlContext.readTensor(this.mlTensor); } - return this.mlContext.readTensor(this.mlTensor); } public canReuseTensor(context: MLContext, dataType: MLOperandDataType, shape: readonly number[]): boolean { @@ -150,6 +223,10 @@ class TensorWrapper { this.tensorShape.every((v, i) => v === shape[i]) ); } + + public setIsInt64ToInt32Converted(isConverted: boolean): void { + this.isInt64ToInt32Converted = isConverted; + } } /** @@ -183,13 +260,22 @@ class TensorIdTracker { shape: readonly number[], copyOld: boolean, ): Promise { + let newDataType = dataType; const context = this.tensorManager.getMLContext(sessionId); + // If the data type is int64 and the context does not support int64, we need to convert it to int32. + const shouldConvertInt64toInt32 = + newDataType === 'int64' && !context.opSupportLimits().input.dataTypes.includes('int64'); + if (shouldConvertInt64toInt32) { + newDataType = 'int32'; + LOG_DEBUG('verbose', () => `[WebNN] TensorIdTracker.ensureTensor: convert dataType from int64 to int32`); + } + if (this.wrapper) { - if (this.wrapper.canReuseTensor(context, dataType, shape)) { + if (this.wrapper.canReuseTensor(context, newDataType, shape)) { return this.wrapper.tensor; } else { if (copyOld) { - if (this.wrapper.byteLength !== calculateByteLength(dataType, shape)) { + if (this.wrapper.byteLength !== calculateByteLength(newDataType, shape)) { throw new Error('Unable to copy data to tensor with different size.'); } this.activeUpload = new Uint8Array(await this.wrapper.read()); @@ -200,9 +286,19 @@ class TensorIdTracker { // eslint-disable-next-line no-bitwise const usage = typeof MLTensorUsage == 'undefined' ? undefined : MLTensorUsage.READ | MLTensorUsage.WRITE; - this.wrapper = await this.tensorManager.getCachedTensor(sessionId, dataType, shape, usage, true, true); + this.wrapper = await this.tensorManager.getCachedTensor( + sessionId, + newDataType, + shape, + usage, + true, + true, + shouldConvertInt64toInt32, + ); if (copyOld && this.activeUpload) { + // We don't need to convert the old int64 data to int32, + // because it has been converted when it was uploaded. this.wrapper.write(this.activeUpload); this.activeUpload = undefined; } @@ -211,9 +307,15 @@ class TensorIdTracker { } public upload(data: Uint8Array): void { + let newData = data; if (this.wrapper) { - if (data.byteLength === this.wrapper.byteLength) { - this.wrapper.write(data); + if (this.wrapper.shouldConvertInt64toInt32) { + // Convert int64 to int32. + newData = convertInt64ToInt32(data, true) as Uint8Array; + this.wrapper.setIsInt64ToInt32Converted(true); + } + if (newData.byteLength === this.wrapper.byteLength) { + this.wrapper.write(newData); return; } else { LOG_DEBUG('verbose', () => 'Data size does not match tensor size. Releasing tensor.'); @@ -222,32 +324,38 @@ class TensorIdTracker { } if (this.activeUpload) { - this.activeUpload.set(data); + this.activeUpload.set(newData); } else { - this.activeUpload = new Uint8Array(data); + this.activeUpload = new Uint8Array(newData); } } public async download(dstBuffer?: ArrayBufferView | ArrayBuffer): Promise { if (this.activeUpload) { + // If this.activeUpload has been converted to int32, we need to convert it back to int64 data. + const dstData = this.wrapper?.isInt64ToInt32Converted + ? (convertInt32ToInt64(this.activeUpload) as Uint8Array) + : this.activeUpload; + if (dstBuffer) { if (dstBuffer instanceof ArrayBuffer) { - new Uint8Array(dstBuffer).set(this.activeUpload); + new Uint8Array(dstBuffer).set(dstData); } else { - new Uint8Array(dstBuffer.buffer, dstBuffer.byteOffset, dstBuffer.byteLength).set(this.activeUpload); + new Uint8Array(dstBuffer.buffer, dstBuffer.byteOffset, dstBuffer.byteLength).set(dstData); } return; } else { - return this.activeUpload.buffer; + return dstData.buffer; } } if (!this.wrapper) { throw new Error('Tensor has not been created.'); } + if (!dstBuffer) { - return this.wrapper.read(); + return this.wrapper.read(this.wrapper?.shouldConvertInt64toInt32); } - return this.wrapper.read(dstBuffer); + return this.wrapper.read(this.wrapper?.shouldConvertInt64toInt32, dstBuffer); } } @@ -367,6 +475,7 @@ class TensorManagerImpl implements TensorManager { usage: MLTensorUsageFlags | undefined, writable: boolean, readable: boolean, + shouldConvertInt64toInt32 = false, ): Promise { const context = this.getMLContext(sessionId); for (const [index, tensor] of this.freeTensors.entries()) { @@ -386,7 +495,7 @@ class TensorManagerImpl implements TensorManager { writable, readable, }); - return new TensorWrapper({ sessionId, context, tensor, dataType, shape }); + return new TensorWrapper({ sessionId, context, tensor, dataType, shape, shouldConvertInt64toInt32 }); } /** diff --git a/js/web/lib/wasm/jsep/webnn/webnn.d.ts b/js/web/lib/wasm/jsep/webnn/webnn.d.ts index c513b2ec2ed8b..0ebff457d5b33 100644 --- a/js/web/lib/wasm/jsep/webnn/webnn.d.ts +++ b/js/web/lib/wasm/jsep/webnn/webnn.d.ts @@ -415,4 +415,13 @@ interface MLContext { readTensor(sourceTensor: MLTensor): Promise; readTensor(sourceTensor: MLTensor, destinationData: ArrayBufferView|ArrayBuffer): Promise; dispatch(graph: MLGraph, inputs: MLNamedTensor, outputs: MLNamedTensor): void; + opSupportLimits() : MLOpSupportLimits; +} + +interface MLOpSupportLimits { + input: MLSupportLimits; +} + +interface MLSupportLimits { + dataTypes: MLOperandDataType[]; } diff --git a/js/web/lib/wasm/proxy-messages.ts b/js/web/lib/wasm/proxy-messages.ts index 559f319a10f66..2584203d4503b 100644 --- a/js/web/lib/wasm/proxy-messages.ts +++ b/js/web/lib/wasm/proxy-messages.ts @@ -46,7 +46,13 @@ export type UnserializableTensorMetadata = */ export type TensorMetadata = SerializableTensorMetadata | UnserializableTensorMetadata; -export type SerializableSessionMetadata = [sessionHandle: number, inputNames: string[], outputNames: string[]]; +export type SerializableSessionMetadata = [ + sessionHandle: number, + inputNames: string[], + outputNames: string[], + inputMetadata: InferenceSession.ValueMetadata[], + outputMetadata: InferenceSession.ValueMetadata[], +]; export type SerializableInternalBuffer = [bufferOffset: number, bufferLength: number]; diff --git a/js/web/lib/wasm/proxy-wrapper.ts b/js/web/lib/wasm/proxy-wrapper.ts index 5d97bb83e3475..30b1f5101e5f2 100644 --- a/js/web/lib/wasm/proxy-wrapper.ts +++ b/js/web/lib/wasm/proxy-wrapper.ts @@ -12,7 +12,11 @@ import { } from './proxy-messages'; import * as core from './wasm-core-impl'; import { initializeWebAssembly } from './wasm-factory'; -import { importProxyWorker, inferWasmPathPrefixFromScriptSrc } from './wasm-utils-import'; +import { + importProxyWorker, + inferWasmPathPrefixFromScriptSrc, + isEsmImportMetaUrlHardcodedAsFileUri, +} from './wasm-utils-import'; const isProxy = (): boolean => !!env.wasm.proxy && typeof document !== 'undefined'; let proxyWorker: Worker | undefined; @@ -116,7 +120,7 @@ export const initializeWebAssemblyAndOrtRuntime = async (): Promise => { BUILD_DEFS.IS_ESM && BUILD_DEFS.ENABLE_BUNDLE_WASM_JS && !message.in!.wasm.wasmPaths && - (objectUrl || BUILD_DEFS.ESM_IMPORT_META_URL?.startsWith('file:')) + (objectUrl || isEsmImportMetaUrlHardcodedAsFileUri) ) { // for a build bundled the wasm JS, if either of the following conditions is met: // - the proxy worker is loaded from a blob URL diff --git a/js/web/lib/wasm/session-handler-inference.ts b/js/web/lib/wasm/session-handler-inference.ts index c19043cc3637f..1fa2216b57219 100644 --- a/js/web/lib/wasm/session-handler-inference.ts +++ b/js/web/lib/wasm/session-handler-inference.ts @@ -57,8 +57,10 @@ export const decodeTensorMetadata = (tensor: TensorMetadata): Tensor => { export class OnnxruntimeWebAssemblySessionHandler implements InferenceSessionHandler { private sessionId: number; - inputNames: string[]; - outputNames: string[]; + inputNames: readonly string[]; + outputNames: readonly string[]; + inputMetadata: readonly InferenceSession.ValueMetadata[]; + outputMetadata: readonly InferenceSession.ValueMetadata[]; async fetchModelAndCopyToWasmMemory(path: string): Promise { // fetch model from url and move to wasm heap. @@ -82,7 +84,10 @@ export class OnnxruntimeWebAssemblySessionHandler implements InferenceSessionHan model = pathOrBuffer; } - [this.sessionId, this.inputNames, this.outputNames] = await createSession(model, options); + [this.sessionId, this.inputNames, this.outputNames, this.inputMetadata, this.outputMetadata] = await createSession( + model, + options, + ); TRACE_FUNC_END(); } diff --git a/js/web/lib/wasm/session-options.ts b/js/web/lib/wasm/session-options.ts index 17e564247863d..89a4484e5a1c4 100644 --- a/js/web/lib/wasm/session-options.ts +++ b/js/web/lib/wasm/session-options.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { InferenceSession } from 'onnxruntime-common'; +import type { InferenceSession } from 'onnxruntime-common'; import { getInstance } from './wasm-factory'; import { allocWasmString, checkLastError, iterateExtraOptions } from './wasm-utils'; @@ -54,13 +54,28 @@ const appendDefaultOptions = (options: InferenceSession.SessionOptions): void => } }; -const setExecutionProviders = ( +const appendSessionConfig = (sessionOptionsHandle: number, key: string, value: string, allocs: number[]): void => { + const keyDataOffset = allocWasmString(key, allocs); + const valueDataOffset = allocWasmString(value, allocs); + if (getInstance()._OrtAddSessionConfigEntry(sessionOptionsHandle, keyDataOffset, valueDataOffset) !== 0) { + checkLastError(`Can't set a session config entry: ${key} - ${value}.`); + } +}; + +const appendEpOption = (epOptions: Array<[number, number]>, key: string, value: string, allocs: number[]): void => { + const keyDataOffset = allocWasmString(key, allocs); + const valueDataOffset = allocWasmString(value, allocs); + epOptions.push([keyDataOffset, valueDataOffset]); +}; + +const setExecutionProviders = async ( sessionOptionsHandle: number, executionProviders: readonly InferenceSession.ExecutionProviderConfig[], allocs: number[], -): void => { +): Promise => { for (const ep of executionProviders) { let epName = typeof ep === 'string' ? ep : ep.name; + const epOptions: Array<[number, number]> = []; // check EP name switch (epName) { @@ -71,26 +86,44 @@ const setExecutionProviders = ( // const context = (webnnOptions as InferenceSession.WebNNOptionsWithMLContext)?.context; const deviceType = (webnnOptions as InferenceSession.WebNNContextOptions)?.deviceType; if (deviceType) { - const keyDataOffset = allocWasmString('deviceType', allocs); - const valueDataOffset = allocWasmString(deviceType, allocs); - if (getInstance()._OrtAddSessionConfigEntry(sessionOptionsHandle, keyDataOffset, valueDataOffset) !== 0) { - checkLastError(`Can't set a session config entry: 'deviceType' - ${deviceType}.`); - } + appendSessionConfig(sessionOptionsHandle, 'deviceType', deviceType, allocs); } } break; case 'webgpu': - epName = 'JS'; - if (typeof ep !== 'string') { - const webgpuOptions = ep as InferenceSession.WebGpuExecutionProviderOption; - if (webgpuOptions?.preferredLayout) { - if (webgpuOptions.preferredLayout !== 'NCHW' && webgpuOptions.preferredLayout !== 'NHWC') { - throw new Error(`preferredLayout must be either 'NCHW' or 'NHWC': ${webgpuOptions.preferredLayout}`); + if (BUILD_DEFS.USE_WEBGPU_EP) { + epName = 'WebGPU'; + let customDevice: GPUDevice | undefined; + + if (typeof ep !== 'string') { + const customOptions = ep as unknown as { device: GPUDevice }; + if (customOptions.device) { + if (typeof GPUDevice !== 'undefined' && customOptions.device instanceof GPUDevice) { + customDevice = customOptions.device; + } else { + throw new Error('Invalid GPU device set in WebGPU EP options.'); + } } - const keyDataOffset = allocWasmString('preferredLayout', allocs); - const valueDataOffset = allocWasmString(webgpuOptions.preferredLayout, allocs); - if (getInstance()._OrtAddSessionConfigEntry(sessionOptionsHandle, keyDataOffset, valueDataOffset) !== 0) { - checkLastError(`Can't set a session config entry: 'preferredLayout' - ${webgpuOptions.preferredLayout}.`); + + // TODO: handle more options + } + + const info = getInstance().webgpuRegisterDevice!(customDevice); + if (info) { + const [deviceId, instanceHandle, deviceHandle] = info; + appendEpOption(epOptions, 'deviceId', deviceId.toString(), allocs); + appendEpOption(epOptions, 'webgpuInstance', instanceHandle.toString(), allocs); + appendEpOption(epOptions, 'webgpuDevice', deviceHandle.toString(), allocs); + } + } else { + epName = 'JS'; + if (typeof ep !== 'string') { + const webgpuOptions = ep as InferenceSession.WebGpuExecutionProviderOption; + if (webgpuOptions?.preferredLayout) { + if (webgpuOptions.preferredLayout !== 'NCHW' && webgpuOptions.preferredLayout !== 'NHWC') { + throw new Error(`preferredLayout must be either 'NCHW' or 'NHWC': ${webgpuOptions.preferredLayout}`); + } + appendSessionConfig(sessionOptionsHandle, 'preferredLayout', webgpuOptions.preferredLayout, allocs); } } } @@ -103,13 +136,34 @@ const setExecutionProviders = ( } const epNameDataOffset = allocWasmString(epName, allocs); - if (getInstance()._OrtAppendExecutionProvider(sessionOptionsHandle, epNameDataOffset) !== 0) { + const epOptionsCount = epOptions.length; + let keysOffset = 0; + let valuesOffset = 0; + if (epOptionsCount > 0) { + keysOffset = getInstance()._malloc(epOptionsCount * getInstance().PTR_SIZE); + allocs.push(keysOffset); + valuesOffset = getInstance()._malloc(epOptionsCount * getInstance().PTR_SIZE); + allocs.push(valuesOffset); + for (let i = 0; i < epOptionsCount; i++) { + getInstance().setValue(keysOffset + i * getInstance().PTR_SIZE, epOptions[i][0], '*'); + getInstance().setValue(valuesOffset + i * getInstance().PTR_SIZE, epOptions[i][1], '*'); + } + } + if ( + (await getInstance()._OrtAppendExecutionProvider( + sessionOptionsHandle, + epNameDataOffset, + keysOffset, + valuesOffset, + epOptionsCount, + )) !== 0 + ) { checkLastError(`Can't append execution provider: ${epName}.`); } } }; -export const setSessionOptions = (options?: InferenceSession.SessionOptions): [number, number[]] => { +export const setSessionOptions = async (options?: InferenceSession.SessionOptions): Promise<[number, number[]]> => { const wasm = getInstance(); let sessionOptionsHandle = 0; const allocs: number[] = []; @@ -155,20 +209,19 @@ export const setSessionOptions = (options?: InferenceSession.SessionOptions): [n } if (sessionOptions.executionProviders) { - setExecutionProviders(sessionOptionsHandle, sessionOptions.executionProviders, allocs); + await setExecutionProviders(sessionOptionsHandle, sessionOptions.executionProviders, allocs); } if (sessionOptions.enableGraphCapture !== undefined) { if (typeof sessionOptions.enableGraphCapture !== 'boolean') { throw new Error(`enableGraphCapture must be a boolean value: ${sessionOptions.enableGraphCapture}`); } - const keyDataOffset = allocWasmString('enableGraphCapture', allocs); - const valueDataOffset = allocWasmString(sessionOptions.enableGraphCapture.toString(), allocs); - if (wasm._OrtAddSessionConfigEntry(sessionOptionsHandle, keyDataOffset, valueDataOffset) !== 0) { - checkLastError( - `Can't set a session config entry: 'enableGraphCapture' - ${sessionOptions.enableGraphCapture}.`, - ); - } + appendSessionConfig( + sessionOptionsHandle, + 'enableGraphCapture', + sessionOptions.enableGraphCapture.toString(), + allocs, + ); } if (sessionOptions.freeDimensionOverrides) { @@ -188,12 +241,7 @@ export const setSessionOptions = (options?: InferenceSession.SessionOptions): [n if (sessionOptions.extra !== undefined) { iterateExtraOptions(sessionOptions.extra, '', new WeakSet>(), (key, value) => { - const keyDataOffset = allocWasmString(key, allocs); - const valueDataOffset = allocWasmString(value, allocs); - - if (wasm._OrtAddSessionConfigEntry(sessionOptionsHandle, keyDataOffset, valueDataOffset) !== 0) { - checkLastError(`Can't set a session config entry: ${key} - ${value}.`); - } + appendSessionConfig(sessionOptionsHandle, key, value, allocs); }); } diff --git a/js/web/lib/wasm/wasm-core-impl.ts b/js/web/lib/wasm/wasm-core-impl.ts index 4bccfa76fdda3..8dd643293937b 100644 --- a/js/web/lib/wasm/wasm-core-impl.ts +++ b/js/web/lib/wasm/wasm-core-impl.ts @@ -102,11 +102,20 @@ export const initRuntime = async (env: Env): Promise => { * @param epName */ export const initEp = async (env: Env, epName: string): Promise => { + // initialize ASYNCIFY support + getInstance().asyncInit?.(); + + if (epName === 'webgpu' && BUILD_DEFS.USE_WEBGPU_EP) { + getInstance().webgpuInit!((device) => { + env.webgpu.device = device; + }); + } + if (!BUILD_DEFS.DISABLE_JSEP) { // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires const initJsep = require('./jsep/init').init; - if (epName === 'webgpu') { + if (epName === 'webgpu' && !BUILD_DEFS.USE_WEBGPU_EP) { // perform WebGPU availability check if (typeof navigator === 'undefined' || !navigator.gpu) { throw new Error('WebGPU is not supported in current environment'); @@ -220,6 +229,49 @@ const getSessionInputOutputCount = (sessionHandle: number): [number, number] => } }; +const getSessionInputOutputMetadata = ( + sessionHandle: number, + index: number, +): [nameOffset: number, elementType: number, dims?: Array] => { + const wasm = getInstance(); + const stack = wasm.stackSave(); + let metadataOffset = 0; + try { + const ptrSize = wasm.PTR_SIZE; + const dataOffset = wasm.stackAlloc(2 * ptrSize); + const errorCode = wasm._OrtGetInputOutputMetadata(sessionHandle, index, dataOffset, dataOffset + ptrSize); + if (errorCode !== 0) { + checkLastError("Can't get session input/output metadata."); + } + const nameOffset = Number(wasm.getValue(dataOffset, '*')); + metadataOffset = Number(wasm.getValue(dataOffset + ptrSize, '*')); + // get element type + const elementType = wasm.HEAP32[metadataOffset / 4]; + if (elementType === 0) { + return [nameOffset, 0]; // non-tensor + } + + // get dims count + const dimsCount = wasm.HEAPU32[metadataOffset / 4 + 1]; + // get dims + const dims: Array = []; + for (let i = 0; i < dimsCount; i++) { + const symbolicDimNameOffset = Number(wasm.getValue(metadataOffset + 8 + i * ptrSize, '*')); + dims.push( + symbolicDimNameOffset !== 0 + ? wasm.UTF8ToString(symbolicDimNameOffset) + : Number(wasm.getValue(metadataOffset + 8 + (i + dimsCount) * ptrSize, '*')), + ); + } + return [nameOffset, elementType, dims]; + } finally { + wasm.stackRestore(stack); + if (metadataOffset !== 0) { + wasm._OrtFree(metadataOffset); + } + } +}; + /** * allocate the memory and memcpy the external buffer. * @@ -270,7 +322,7 @@ export const createSession = async ( const outputNamesUTF8Encoded = []; try { - [sessionOptionsHandle, allocs] = setSessionOptions(options); + [sessionOptionsHandle, allocs] = await setSessionOptions(options); if (options?.externalData && wasm.mountExternalData) { const loadingPromises = []; @@ -278,7 +330,7 @@ export const createSession = async ( const path = typeof file === 'string' ? file : file.path; loadingPromises.push( loadFile(typeof file === 'string' ? file : file.data).then((data) => { - wasm.mountExternalData!(path, data); + wasm.mountExternalData(path, data); }), ); } @@ -300,18 +352,19 @@ export const createSession = async ( if (context) { wasm.currentContext = context as MLContext; } else if (gpuDevice) { - wasm.currentContext = await wasm.jsepCreateMLContext!(gpuDevice); + wasm.currentContext = await wasm.webnnCreateMLContext!(gpuDevice); } else { - wasm.currentContext = await wasm.jsepCreateMLContext!({ deviceType, powerPreference }); + wasm.currentContext = await wasm.webnnCreateMLContext!({ deviceType, powerPreference }); } } else { - wasm.currentContext = await wasm.jsepCreateMLContext!(); + wasm.currentContext = await wasm.webnnCreateMLContext!(); } break; } } sessionHandle = await wasm._OrtCreateSession(modelDataOffset, modelDataLength, sessionOptionsHandle); + wasm.webgpuOnCreateSession?.(sessionHandle); if (sessionHandle === 0) { checkLastError("Can't create a session."); } @@ -320,7 +373,7 @@ export const createSession = async ( // clear current MLContext after session creation if (wasm.currentContext) { - wasm.jsepRegisterMLContext!(sessionHandle, wasm.currentContext); + wasm.webnnRegisterMLContext!(sessionHandle, wasm.currentContext); wasm.currentContext = undefined; wasm.shouldTransferToMLTensor = true; } @@ -331,23 +384,36 @@ export const createSession = async ( const inputNames = []; const outputNames = []; + const inputMetadata: InferenceSession.ValueMetadata[] = []; + const outputMetadata: InferenceSession.ValueMetadata[] = []; const outputPreferredLocations: SupportedTensorDataLocationForInputOutput[] = []; for (let i = 0; i < inputCount; i++) { - const name = wasm._OrtGetInputName(sessionHandle, i); - if (name === 0) { + const [nameOffset, elementType, shape] = getSessionInputOutputMetadata(sessionHandle, i); + if (nameOffset === 0) { checkLastError("Can't get an input name."); } - inputNamesUTF8Encoded.push(name); - inputNames.push(wasm.UTF8ToString(name)); + inputNamesUTF8Encoded.push(nameOffset); + const name = wasm.UTF8ToString(nameOffset); + inputNames.push(name); + inputMetadata.push( + elementType === 0 + ? { name, isTensor: false } + : { name, isTensor: true, type: tensorDataTypeEnumToString(elementType), shape: shape! }, + ); } for (let i = 0; i < outputCount; i++) { - const name = wasm._OrtGetOutputName(sessionHandle, i); - if (name === 0) { + const [nameOffset, elementType, shape] = getSessionInputOutputMetadata(sessionHandle, i + inputCount); + if (nameOffset === 0) { checkLastError("Can't get an output name."); } - outputNamesUTF8Encoded.push(name); - const nameString = wasm.UTF8ToString(name); + outputNamesUTF8Encoded.push(nameOffset); + const nameString = wasm.UTF8ToString(nameOffset); outputNames.push(nameString); + outputMetadata.push( + elementType === 0 + ? { name: nameString, isTensor: false } + : { name: nameString, isTensor: true, type: tensorDataTypeEnumToString(elementType), shape: shape! }, + ); if (!BUILD_DEFS.DISABLE_JSEP) { if (enableGraphCapture && options?.preferredOutputLocation === undefined) { @@ -393,7 +459,7 @@ export const createSession = async ( enableGraphCapture, false, ]); - return [sessionHandle, inputNames, outputNames]; + return [sessionHandle, inputNames, outputNames, inputMetadata, outputMetadata]; } catch (e) { inputNamesUTF8Encoded.forEach((buf) => wasm._OrtFree(buf)); outputNamesUTF8Encoded.forEach((buf) => wasm._OrtFree(buf)); @@ -444,6 +510,8 @@ export const releaseSession = (sessionId: number): void => { } wasm.jsepOnReleaseSession?.(sessionId); + wasm.webnnOnReleaseSession?.(sessionId); + wasm.webgpuOnReleaseSession?.(sessionId); inputNamesUTF8Encoded.forEach((buf) => wasm._OrtFree(buf)); outputNamesUTF8Encoded.forEach((buf) => wasm._OrtFree(buf)); @@ -458,6 +526,7 @@ export const prepareInputOutputTensor = async ( tensorHandles: number[], allocs: number[], sessionId: number, + tensorNameUTF8Encoded: number, index: number, enableGraphCapture = false, ): Promise => { @@ -491,16 +560,25 @@ export const prepareInputOutputTensor = async ( const gpuBuffer = tensor[2].gpuBuffer; dataByteLength = calculateTensorSizeInBytes(tensorDataTypeStringToEnum(dataType), dims)!; - const registerBuffer = wasm.jsepRegisterBuffer; - if (!registerBuffer) { - throw new Error('Tensor location "gpu-buffer" is not supported without using WebGPU.'); + if (BUILD_DEFS.USE_WEBGPU_EP) { + const registerBuffer = wasm.webgpuRegisterBuffer; + if (!registerBuffer) { + throw new Error('Tensor location "gpu-buffer" is not supported without using WebGPU.'); + } + + rawData = registerBuffer(gpuBuffer, sessionId); + } else { + const registerBuffer = wasm.jsepRegisterBuffer; + if (!registerBuffer) { + throw new Error('Tensor location "gpu-buffer" is not supported without using WebGPU.'); + } + rawData = registerBuffer(sessionId, index, gpuBuffer, dataByteLength); } - rawData = registerBuffer(sessionId, index, gpuBuffer, dataByteLength); } else if (location === 'ml-tensor') { const mlTensor = tensor[2].mlTensor as MLTensor; dataByteLength = calculateTensorSizeInBytes(tensorDataTypeStringToEnum(dataType), dims)!; - const registerMLTensor = wasm.jsepRegisterMLTensor; + const registerMLTensor = wasm.webnnRegisterMLTensor; if (!registerMLTensor) { throw new Error('Tensor location "ml-tensor" is not supported without using WebNN.'); } @@ -520,17 +598,16 @@ export const prepareInputOutputTensor = async ( wasm.setValue(rawData + i * ptrSize, allocWasmString(data[i], allocs), '*'); } } else { - const isGraphInput = wasm.jsepIsGraphInput; + const isGraphInput = wasm.webnnIsGraphInput; if (dataType !== 'string' && isGraphInput) { - const tensorNameUTF8 = wasm._OrtGetInputName(sessionId, index); - const tensorName = wasm.UTF8ToString(tensorNameUTF8); + const tensorName = wasm.UTF8ToString(tensorNameUTF8Encoded); // Promote the tensor to 'ml-tensor' if it is a graph input. if (isGraphInput(sessionId, tensorName)) { const dataTypeEnum = tensorDataTypeStringToEnum(dataType); dataByteLength = calculateTensorSizeInBytes(dataTypeEnum, dims)!; actualLocation = 'ml-tensor'; - const createTemporaryTensor = wasm.jsepCreateTemporaryTensor; - const uploadTensor = wasm.jsepUploadTensor; + const createTemporaryTensor = wasm.webnnCreateTemporaryTensor; + const uploadTensor = wasm.webnnUploadTensor; if (!createTemporaryTensor || !uploadTensor) { throw new Error('Tensor location "ml-tensor" is not supported without using WebNN.'); } @@ -623,6 +700,7 @@ export const run = async ( inputTensorHandles, inputOutputAllocs, sessionId, + inputNamesUTF8Encoded[inputIndices[i]], inputIndices[i], enableGraphCapture, ); @@ -635,6 +713,7 @@ export const run = async ( outputTensorHandles, inputOutputAllocs, sessionId, + outputNamesUTF8Encoded[outputIndices[i]], inputCount + outputIndices[i], enableGraphCapture, ); @@ -702,6 +781,7 @@ export const run = async ( } wasm.jsepOnRunStart?.(sessionHandle); + wasm.webnnOnRunStart?.(sessionHandle); let errorCode: number; if (!BUILD_DEFS.DISABLE_JSEP && ioBindingState) { @@ -791,7 +871,7 @@ export const run = async ( // If a certain output's preferred location is GPU but the tensor is empty, we still need to create a CPU // tensor for it. There is no mapping GPU buffer for an empty tensor. if (preferredLocation === 'gpu-buffer' && size > 0) { - const getBuffer = wasm.jsepGetBuffer; + const getBuffer = BUILD_DEFS.USE_WEBGPU_EP ? wasm.webgpuGetBuffer : wasm.jsepGetBuffer; if (!getBuffer) { throw new Error('preferredLocation "gpu-buffer" is not supported without using WebGPU.'); } @@ -804,29 +884,58 @@ export const run = async ( // do not release the tensor right now. it will be released when user calls tensor.dispose(). keepOutputTensor = true; - output.push([ - type, - dims, - { - gpuBuffer, - download: wasm.jsepCreateDownloader!(gpuBuffer, bufferSize, type), - dispose: () => { - if (wasm._OrtReleaseTensor(tensor) !== 0) { - checkLastError("Can't release tensor."); - } + if (BUILD_DEFS.USE_WEBGPU_EP) { + wasm.webgpuRegisterBuffer!(gpuBuffer, sessionId, dataOffset); + const downloadDataFunction = wasm.webgpuCreateDownloader!(gpuBuffer, bufferSize, sessionId); + output.push([ + type, + dims, + { + gpuBuffer, + download: async () => { + const arrayBuffer = await downloadDataFunction(); + const data = new (tensorTypeToTypedArrayConstructor(type!))(arrayBuffer); + return data as Tensor.DataTypeMap[Tensor.GpuBufferDataTypes]; + }, + dispose: () => { + if (wasm._OrtReleaseTensor(tensor) !== 0) { + checkLastError("Can't release tensor."); + } + }, }, - }, - 'gpu-buffer', - ]); + 'gpu-buffer', + ]); + } else { + output.push([ + type, + dims, + { + gpuBuffer, + download: wasm.jsepCreateDownloader!(gpuBuffer, bufferSize, type), + dispose: () => { + if (wasm._OrtReleaseTensor(tensor) !== 0) { + checkLastError("Can't release tensor."); + } + }, + }, + 'gpu-buffer', + ]); + } } else if (preferredLocation === 'ml-tensor' && size > 0) { - const ensureTensor = wasm.jsepEnsureTensor; - if (!ensureTensor) { + const ensureTensor = wasm.webnnEnsureTensor; + const isInt64Supported = wasm.webnnIsInt64Supported; + if (!ensureTensor || !isInt64Supported) { throw new Error('preferredLocation "ml-tensor" is not supported without using WebNN.'); } const tensorSize = calculateTensorSizeInBytes(dataType, size); if (tensorSize === undefined || !isMLTensorSupportedType(type)) { throw new Error(`Unsupported data type: ${type}`); } + if (type === 'int64' && !isInt64Supported(sessionId)) { + throw new Error( + `preferredLocation "ml-tensor" for int64 output is not supported by current WebNN Context.`, + ); + } // If the graph has been partitioned, the output tensor may have not been created. For this reason, we use // ensureTensor to get/create the MLTensor. In which case, we don't need to copy the data if a new tensor @@ -841,9 +950,9 @@ export const run = async ( dims, { mlTensor, - download: wasm.jsepCreateMLTensorDownloader!(dataOffset, type), + download: wasm.webnnCreateMLTensorDownloader!(dataOffset, type), dispose: () => { - wasm.jsepReleaseTensorId!(dataOffset); + wasm.webnnReleaseTensorId!(dataOffset); wasm._OrtReleaseTensor(tensor); }, }, @@ -866,7 +975,7 @@ export const run = async ( if (!keepOutputTensor) { wasm._OrtReleaseTensor(tensor); } - wasm.jsepOnRunEnd?.(sessionHandle); + wasm.webnnOnRunEnd?.(sessionHandle); } } @@ -887,6 +996,18 @@ export const run = async ( } finally { wasm.stackRestore(beforeRunStack); + if (BUILD_DEFS.USE_WEBGPU_EP) { + inputTensors.forEach((t) => { + if (t && t[3] === 'gpu-buffer') { + wasm.webgpuUnregisterBuffer!(t[2].gpuBuffer); + } + }); + outputTensors.forEach((t) => { + if (t && t[3] === 'gpu-buffer') { + wasm.webgpuUnregisterBuffer!(t[2].gpuBuffer); + } + }); + } inputTensorHandles.forEach((v) => wasm._OrtReleaseTensor(v)); outputTensorHandles.forEach((v) => wasm._OrtReleaseTensor(v)); inputOutputAllocs.forEach((p) => wasm._free(p)); diff --git a/js/web/lib/wasm/wasm-factory.ts b/js/web/lib/wasm/wasm-factory.ts index 0f49d25040409..23eb2f0978feb 100644 --- a/js/web/lib/wasm/wasm-factory.ts +++ b/js/web/lib/wasm/wasm-factory.ts @@ -64,6 +64,34 @@ const isSimdSupported = (): boolean => { } }; +const isRelaxedSimdSupported = (): boolean => { + try { + // Test for WebAssembly Relaxed SIMD capability (for both browsers and Node.js) + // This typed array is a WebAssembly program containing Relaxed SIMD instructions. + + // The binary data is generated from the following code by wat2wasm: + // (module + // (func (result v128) + // i32.const 1 + // i8x16.splat + // i32.const 2 + // i8x16.splat + // i32.const 3 + // i8x16.splat + // i32x4.relaxed_dot_i8x16_i7x16_add_s + // ) + // ) + return WebAssembly.validate( + new Uint8Array([ + 0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 96, 0, 1, 123, 3, 2, 1, 0, 10, 19, 1, 17, 0, 65, 1, 253, 15, 65, 2, 253, + 15, 65, 3, 253, 15, 253, 147, 2, 11, + ]), + ); + } catch (e) { + return false; + } +}; + export const initializeWebAssembly = async (flags: Env.WebAssemblyFlags): Promise => { if (initialized) { return Promise.resolve(); @@ -82,7 +110,14 @@ export const initializeWebAssembly = async (flags: Env.WebAssemblyFlags): Promis let numThreads = flags.numThreads!; // ensure SIMD is supported - if (!isSimdSupported()) { + if (flags.simd === false) { + // skip SIMD feature checking as it is disabled explicitly by user + } else if (flags.simd === 'relaxed') { + // check if relaxed SIMD is supported + if (!isRelaxedSimdSupported()) { + throw new Error('Relaxed WebAssembly SIMD is not supported in the current environment.'); + } + } else if (!isSimdSupported()) { throw new Error('WebAssembly SIMD is not supported in the current environment.'); } diff --git a/js/web/lib/wasm/wasm-types.ts b/js/web/lib/wasm/wasm-types.ts index b4871e145f4d7..b2ca8480f1546 100644 --- a/js/web/lib/wasm/wasm-types.ts +++ b/js/web/lib/wasm/wasm-types.ts @@ -41,18 +41,6 @@ export declare namespace JSEP { type DownloadTensorFunction = (tensorId: number, dstBuffer: ArrayBufferView | ArrayBuffer) => Promise; export interface Module extends WebGpuModule, WebNnModule { - /** - * Mount the external data file to an internal map, which will be used during session initialization. - * - * @param externalDataFilePath - specify the relative path of the external data file. - * @param externalDataFileData - specify the content data. - */ - mountExternalData(externalDataFilePath: string, externalDataFileData: Uint8Array): void; - /** - * Unmount all external data files from the internal map. - */ - unmountExternalData(): void; - /** * This is the entry of JSEP initialization. This function is called once when initializing ONNX Runtime per * backend. This function initializes Asyncify support. If name is 'webgpu', also initializes WebGPU backend and @@ -168,12 +156,26 @@ export declare namespace JSEP { */ shouldTransferToMLTensor: boolean; + /** + * [exported from pre-jsep.js] Called when InferenceSession.run started. This function will be called before + * _OrtRun[WithBinding]() is called. + * @param sessionId - specify the session ID. + */ + webnnOnRunStart: (sessionId: number) => void; + /** + * [exported from pre-jsep.js] Release a session. This function will be called before _OrtReleaseSession() is + * called. + * @param sessionId - specify the session ID. + * @returns + */ + webnnOnReleaseSession: (sessionId: number) => void; + /** * [exported from pre-jsep.js] Called when InferenceSession.run finished. This function will be called after * _OrtRun[WithBinding]() is called. * @param sessionId - specify the session ID. */ - jsepOnRunEnd: (sessionId: number) => void; + webnnOnRunEnd: (sessionId: number) => void; /** * [exported from pre-jsep.js] Register MLContext for a session. @@ -181,18 +183,18 @@ export declare namespace JSEP { * @param context - specify the MLContext. * @returns */ - jsepRegisterMLContext: (sessionId: number, context: MLContext) => void; + webnnRegisterMLContext: (sessionId: number, context: MLContext) => void; /** * [exported from pre-jsep.js] Reserve a MLTensor ID attached to the current session. * @returns the MLTensor ID. */ - jsepReserveTensorId: () => number; + webnnReserveTensorId: () => number; /** * [exported from pre-jsep.js] Release an MLTensor ID from use and destroys underlying MLTensor if no longer in use. * @param tensorId - specify the MLTensor ID. * @returns */ - jsepReleaseTensorId: (tensorId: number) => void; + webnnReleaseTensorId: (tensorId: number) => void; /** * [exported from pre-jsep.js] Ensure that an MLTensor of a given type and shape exists for a MLTensor ID. * @param sessionId - specify the session ID or current active session ID if undefined. @@ -202,7 +204,7 @@ export declare namespace JSEP { * @param copyOld - specify whether to copy the old tensor if a new tensor was created. * @returns the MLTensor associated with the tensor ID. */ - jsepEnsureTensor: ( + webnnEnsureTensor: ( sessionId: number | undefined, tensorId: number, dataType: DataType, @@ -215,20 +217,20 @@ export declare namespace JSEP { * @param data - specify the data to upload. It can be a TensorProto::data_type or a WebNN MLOperandDataType. * @returns */ - jsepUploadTensor: (tensorId: number, data: Uint8Array) => void; + webnnUploadTensor: (tensorId: number, data: Uint8Array) => void; /** * [exported from pre-jsep.js] Download data from an MLTensor. * @param tensorId - specify the MLTensor ID. * @returns the downloaded data. */ - jsepDownloadTensor: (tensorId: number, dstBuffer: ArrayBufferView | ArrayBuffer) => Promise; + webnnDownloadTensor: (tensorId: number, dstBuffer: ArrayBufferView | ArrayBuffer) => Promise; /** * [exported from pre-jsep.js] Creates a downloader function to download data from an MLTensor. * @param tensorId - specify the MLTensor ID. * @param type - specify the data type. * @returns the downloader function. */ - jsepCreateMLTensorDownloader: ( + webnnCreateMLTensorDownloader: ( tensorId: number, type: Tensor.MLTensorDataTypes, ) => () => Promise; @@ -240,7 +242,7 @@ export declare namespace JSEP { * @param dimensions - specify the dimensions. * @returns the MLTensor ID for the external MLTensor. */ - jsepRegisterMLTensor: ( + webnnRegisterMLTensor: ( sessionId: number, tensor: MLTensor, onnxDataType: DataType, @@ -252,7 +254,7 @@ export declare namespace JSEP { * @param optionsOrGpuDevice - specify the options or GPUDevice. * @returns */ - jsepCreateMLContext(optionsOrGpuDevice?: MLContextOptions | GPUDevice): Promise; + webnnCreateMLContext(optionsOrGpuDevice?: MLContextOptions | GPUDevice): Promise; /** * [exported from pre-jsep.js] Register a WebNN Constant operand from external data. @@ -261,28 +263,30 @@ export declare namespace JSEP { * @param dataLength - specify the external data length. * @param builder - specify the MLGraphBuilder used for constructing the Constant. * @param desc - specify the MLOperandDescriptor of the Constant. + * @param shouldConvertInt64ToInt32 - specify whether to convert int64 to int32. * @returns the WebNN Constant operand for the specified external data. */ - jsepRegisterMLConstant( + webnnRegisterMLConstant( externalFilePath: string, dataOffset: number, dataLength: number, builder: MLGraphBuilder, desc: MLOperandDescriptor, + shouldConvertInt64ToInt32: boolean, ): MLOperand; /** * [exported from pre-jsep.js] Register a WebNN graph input. * @param inputName - specify the input name. */ - jsepRegisterGraphInput: (inputName: string) => void; + webnnRegisterGraphInput: (inputName: string) => void; /** * [exported from pre-jsep.js] Check if a graph input is a WebNN graph input. * @param sessionId - specify the session ID. * @param inputName - specify the input name. * @returns whether the input is a WebNN graph input. */ - jsepIsGraphInput: (sessionId: number, inputName: string) => boolean; + webnnIsGraphInput: (sessionId: number, inputName: string) => boolean; /** * [exported from pre-jsep.js] Create a temporary MLTensor for a session. * @param sessionId - specify the session ID. @@ -290,7 +294,28 @@ export declare namespace JSEP { * @param shape - specify the shape. * @returns the MLTensor ID for the temporary MLTensor. */ - jsepCreateTemporaryTensor: (sessionId: number, dataType: DataType, shape: readonly number[]) => Promise; + webnnCreateTemporaryTensor: (sessionId: number, dataType: DataType, shape: readonly number[]) => Promise; + /** + * [exported from pre-jsep.js] Check if a session's associated WebNN Context supports int64. + * @param sessionId - specify the session ID. + * @returns whether the WebNN Context supports int64. + */ + webnnIsInt64Supported: (sessionId: number) => boolean; + } +} + +export declare namespace WebGpu { + export interface Module { + webgpuInit(setDefaultDevice: (device: GPUDevice) => void): void; + webgpuRegisterDevice( + device?: GPUDevice, + ): undefined | [deviceId: number, instanceHandle: number, deviceHandle: number]; + webgpuOnCreateSession(sessionHandle: number): void; + webgpuOnReleaseSession(sessionHandle: number): void; + webgpuRegisterBuffer(buffer: GPUBuffer, sessionHandle: number, bufferHandle?: number): number; + webgpuUnregisterBuffer(buffer: GPUBuffer): void; + webgpuGetBuffer(bufferHandle: number): GPUBuffer; + webgpuCreateDownloader(gpuBuffer: GPUBuffer, size: number, sessionHandle: number): () => Promise; } } @@ -302,8 +327,12 @@ export interface OrtInferenceAPIs { _OrtCreateSession(dataOffset: number, dataLength: number, sessionOptionsHandle: number): Promise; _OrtReleaseSession(sessionHandle: number): number; _OrtGetInputOutputCount(sessionHandle: number, inputCountOffset: number, outputCountOffset: number): number; - _OrtGetInputName(sessionHandle: number, index: number): number; - _OrtGetOutputName(sessionHandle: number, index: number): number; + _OrtGetInputOutputMetadata( + sessionHandle: number, + index: number, + namePtrOffset: number, + metadataPtrOffset: number, + ): number; _OrtFree(stringHandle: number): number; @@ -358,7 +387,13 @@ export interface OrtInferenceAPIs { logVerbosityLevel: number, optimizedModelFilePath: number, ): number; - _OrtAppendExecutionProvider(sessionOptionsHandle: number, name: number): number; + _OrtAppendExecutionProvider( + sessionOptionsHandle: number, + name: number, + providerOptionsKeys: number, + providerOptionsValues: number, + numKeys: number, + ): Promise; _OrtAddFreeDimensionOverride(sessionOptionsHandle: number, name: number, dim: number): number; _OrtAddSessionConfigEntry(sessionOptionsHandle: number, configKey: number, configValue: number): number; _OrtReleaseSessionOptions(sessionOptionsHandle: number): number; @@ -373,8 +408,11 @@ export interface OrtInferenceAPIs { /** * The interface of the WebAssembly module for ONNX Runtime, compiled from C++ source code by Emscripten. */ -export interface OrtWasmModule extends EmscriptenModule, OrtInferenceAPIs, Partial { - PTR_SIZE: number; +export interface OrtWasmModule + extends EmscriptenModule, + OrtInferenceAPIs, + Partial, + Partial { // #region emscripten functions stackSave(): number; stackRestore(stack: number): void; @@ -387,7 +425,31 @@ export interface OrtWasmModule extends EmscriptenModule, OrtInferenceAPIs, Parti stringToUTF8(str: string, offset: number, maxBytes: number): void; // #endregion + // #region ORT shared + + readonly PTR_SIZE: 4 | 8; + + /** + * Mount the external data file to an internal map, which will be used during session initialization. + * + * @param externalDataFilePath - specify the relative path of the external data file. + * @param externalDataFileData - specify the content data. + */ + mountExternalData(externalDataFilePath: string, externalDataFileData: Uint8Array): void; + /** + * Unmount all external data files from the internal map. + */ + unmountExternalData(): void; + + /** + * This function patches the WebAssembly module to support Asyncify. This function should be called at least once + * before any ORT API is called. + */ + asyncInit?(): void; + + // #endregion + // #region config - numThreads?: number; + readonly numThreads?: number; // #endregion } diff --git a/js/web/lib/wasm/wasm-utils-import.ts b/js/web/lib/wasm/wasm-utils-import.ts index 871b575d71edc..a8e27f6f334bc 100644 --- a/js/web/lib/wasm/wasm-utils-import.ts +++ b/js/web/lib/wasm/wasm-utils-import.ts @@ -11,6 +11,39 @@ import { isNode } from './wasm-utils-env'; */ const origin = isNode || typeof location === 'undefined' ? undefined : location.origin; +/** + * Some bundlers (eg. Webpack) will rewrite `import.meta.url` to a file URL at compile time. + * + * This function checks if `import.meta.url` starts with `file:`, but using the `>` and `<` operators instead of + * `startsWith` function so that code minimizers can remove the dead code correctly. + * + * For example, if we use terser to minify the following code: + * ```js + * if ("file://hard-coded-filename".startsWith("file:")) { + * console.log(1) + * } else { + * console.log(2) + * } + * + * if ("file://hard-coded-filename" > "file:" && "file://hard-coded-filename" < "file;") { + * console.log(3) + * } else { + * console.log(4) + * } + * ``` + * + * The minified code will be: + * ```js + * "file://hard-coded-filename".startsWith("file:")?console.log(1):console.log(2),console.log(3); + * ``` + * + * (use Terser 5.39.0 with default options, https://try.terser.org/) + * + * @returns true if the import.meta.url is hardcoded as a file URI. + */ +export const isEsmImportMetaUrlHardcodedAsFileUri = + BUILD_DEFS.IS_ESM && BUILD_DEFS.ESM_IMPORT_META_URL! > 'file:' && BUILD_DEFS.ESM_IMPORT_META_URL! < 'file;'; + const getScriptSrc = (): string | undefined => { // if Nodejs, return undefined if (isNode) { @@ -26,9 +59,22 @@ const getScriptSrc = (): string | undefined => { // new URL('actual-bundle-name.js', import.meta.url).href // ``` // So that bundler can preprocess the URL correctly. - if (BUILD_DEFS.ESM_IMPORT_META_URL?.startsWith('file:')) { + if (isEsmImportMetaUrlHardcodedAsFileUri) { // if the rewritten URL is a relative path, we need to use the origin to resolve the URL. - return new URL(new URL(BUILD_DEFS.BUNDLE_FILENAME, BUILD_DEFS.ESM_IMPORT_META_URL).href, origin).href; + + // The following is a workaround for Vite. + // + // Vite uses a bundler(rollup/rolldown) that does not rewrite `import.meta.url` to a file URL. So in theory, this + // code path should not be executed in Vite. However, the bundler does not know it and it still try to load the + // following pattern: + // - `return new URL('filename', import.meta.url).href` + // + // By replacing the pattern above with the following code, we can skip the resource loading behavior: + // - `const URL2 = URL; return new URL2('filename', import.meta.url).href;` + // + // And it still works in Webpack. + const URL2 = URL; + return new URL(new URL2(BUILD_DEFS.BUNDLE_FILENAME, BUILD_DEFS.ESM_IMPORT_META_URL).href, origin).href; } return BUILD_DEFS.ESM_IMPORT_META_URL; diff --git a/js/web/package-lock.json b/js/web/package-lock.json index e8e7c45fdc914..a29cf839f20dc 100644 --- a/js/web/package-lock.json +++ b/js/web/package-lock.json @@ -1,12 +1,12 @@ { "name": "onnxruntime-web", - "version": "1.21.0", + "version": "1.22.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "onnxruntime-web", - "version": "1.21.0", + "version": "1.22.0", "license": "MIT", "dependencies": { "flatbuffers": "^25.1.24", @@ -50,7 +50,7 @@ }, "../common": { "name": "onnxruntime-common", - "version": "1.21.0", + "version": "1.22.0", "license": "MIT", "devDependencies": { "typedoc": "^0.25.7" diff --git a/js/web/package.json b/js/web/package.json index 5defe05e78c1f..af02453b0870a 100644 --- a/js/web/package.json +++ b/js/web/package.json @@ -7,7 +7,7 @@ "type": "git" }, "author": "fs-eire", - "version": "1.21.0", + "version": "1.22.0", "jsdelivr": "dist/ort.min.js", "dependencies": { "flatbuffers": "^25.1.24", @@ -72,15 +72,24 @@ "import": "./dist/ort.node.min.mjs", "require": "./dist/ort.node.min.js" }, - "import": "./dist/ort.bundle.min.mjs", + "import": { + "onnxruntime-web-use-extern-wasm": "./dist/ort.min.mjs", + "default": "./dist/ort.bundle.min.mjs" + }, "require": "./dist/ort.min.js" }, "./all": { - "import": "./dist/ort.all.bundle.min.mjs", + "import": { + "onnxruntime-web-use-extern-wasm": "./dist/ort.all.min.mjs", + "default": "./dist/ort.all.bundle.min.mjs" + }, "require": "./dist/ort.all.min.js" }, "./wasm": { - "import": "./dist/ort.wasm.bundle.min.mjs", + "import": { + "onnxruntime-web-use-extern-wasm": "./dist/ort.wasm.min.mjs", + "default": "./dist/ort.wasm.bundle.min.mjs" + }, "require": "./dist/ort.wasm.min.js" }, "./webgl": { @@ -88,7 +97,10 @@ "require": "./dist/ort.webgl.min.js" }, "./webgpu": { - "import": "./dist/ort.webgpu.bundle.min.mjs", + "import": { + "onnxruntime-web-use-extern-wasm": "./dist/ort.webgpu.min.mjs", + "default": "./dist/ort.webgpu.bundle.min.mjs" + }, "require": "./dist/ort.webgpu.min.js" } }, diff --git a/js/web/script/build.ts b/js/web/script/build.ts index 6006de62b41b6..6a9432c2b5acd 100644 --- a/js/web/script/build.ts +++ b/js/web/script/build.ts @@ -27,7 +27,8 @@ const args = minimist(process.argv.slice(2)); * --bundle-mode=node * Build a single ort-web bundle for nodejs. */ -const BUNDLE_MODE: 'prod' | 'dev' | 'perf' | 'node' = args['bundle-mode'] || 'prod'; +const BUNDLE_MODE: 'prod' | 'dev' | 'perf' | 'node' = + process.env.npm_config_bundle_mode || args['bundle-mode'] || 'prod'; /** * --debug @@ -41,7 +42,21 @@ const BUNDLE_MODE: 'prod' | 'dev' | 'perf' | 'node' = args['bundle-mode'] || 'pr * Enable debug mode. In this mode, esbuild metafile feature will be enabled. Full bundle analysis will be saved to a * file as JSON. */ -const DEBUG = args.debug; // boolean|'verbose'|'save' +const DEBUG = process.env.npm_config_debug || args.debug; // boolean|'verbose'|'save' + +/** + * --webgpu-ep + * --no-webgpu-ep (default) + * --webgpu-ep=runtime + * + * Enable or disable the use of WebGPU EP. If enabled, the WebGPU EP will be used. If disabled, the WebGPU backend will + * be used with JSEP. + * + * If set to "runtime", it will be determined at runtime based on the value of `globalThis.WEBGPU_EP`. + * + * (temporary) This flag is used to test the WebGPU EP integration. It will be removed in the future. + */ +const USE_WEBGPU_EP = process.env.npm_config_webgpu_ep ?? args['webgpu-ep'] ?? false; /** * Root folder of the source code: `/js/` @@ -57,6 +72,7 @@ const DEFAULT_DEFINE = { 'BUILD_DEFS.DISABLE_WASM': 'false', 'BUILD_DEFS.DISABLE_WASM_PROXY': 'false', 'BUILD_DEFS.ENABLE_BUNDLE_WASM_JS': 'false', + 'BUILD_DEFS.USE_WEBGPU_EP': USE_WEBGPU_EP === 'runtime' ? 'globalThis.WEBGPU_EP' : JSON.stringify(!!USE_WEBGPU_EP), 'BUILD_DEFS.IS_ESM': 'false', 'BUILD_DEFS.ESM_IMPORT_META_URL': 'undefined', @@ -123,13 +139,17 @@ async function minifyWasmModuleJsForBrowser(filepath: string): Promise { // ``` // with: // ``` - // new Worker(import.meta.url.startsWith('file:') - // ? new URL(BUILD_DEFS.BUNDLE_FILENAME, import.meta.url) - // : new URL(import.meta.url), ... + // new Worker((() => { + // const URL2 = URL; + // return import.meta.url > 'file:' && import.meta.url < 'file;' + // ? new URL2(BUILD_DEFS.BUNDLE_FILENAME, import.meta.url) + // : new URL(import.meta.url); + // })(), ... // ``` // // NOTE: this is a workaround for some bundlers that does not support runtime import.meta.url. - // TODO: in emscripten 3.1.61+, need to update this code. + // + // Check more details in the comment of `isEsmImportMetaUrlHardcodedAsFileUri()` and `getScriptSrc()` in file `lib/wasm/wasm-utils-import.ts`. // First, check if there is exactly one occurrence of "new Worker(new URL(import.meta.url)". const matches = [...contents.matchAll(/new Worker\(new URL\(import\.meta\.url\),/g)]; @@ -142,7 +162,12 @@ async function minifyWasmModuleJsForBrowser(filepath: string): Promise { // Replace the only occurrence. contents = contents.replace( /new Worker\(new URL\(import\.meta\.url\),/, - `new Worker(import.meta.url.startsWith('file:')?new URL(BUILD_DEFS.BUNDLE_FILENAME, import.meta.url):new URL(import.meta.url),`, + `new Worker((() => { + const URL2 = URL; + return (import.meta.url > 'file:' && import.meta.url < 'file;') + ? new URL2(BUILD_DEFS.BUNDLE_FILENAME, import.meta.url) + : new URL(import.meta.url); + })(),`, ); // Use terser to minify the code with special configurations: diff --git a/js/web/script/pull-prebuilt-wasm-artifacts.ts b/js/web/script/pull-prebuilt-wasm-artifacts.ts index a07849a154e01..e5eace8d80dcf 100644 --- a/js/web/script/pull-prebuilt-wasm-artifacts.ts +++ b/js/web/script/pull-prebuilt-wasm-artifacts.ts @@ -8,159 +8,266 @@ // WebAssembly side, so there is no need to rebuild WebAssembly. // // It performs the following operations: -// 1. query build ID for latest successful build on main branch or the specified one from command line argument -// 2. query download URL of build artifacts -// 3. download and unzip the files to folders +// 1. use GitHub Actions REST API as much as possible to get metadata about the status of build and workflow runs. +// - query the main branch if no "run" parameter is specified +// - if "run" is specified, it can be a run ID, PR number, branch name, or commit SHA. Try each possibility. +// +// 2. When the artifact is found, use GitHub CLI (gh) to download the artifacts directly to the dist folder. // import fs from 'fs'; import { bootstrap as globalAgentBootstrap } from 'global-agent'; import https from 'https'; -import jszip from 'jszip'; import path from 'path'; +import minimist from 'minimist'; +import { execSync } from 'child_process'; const HELP_MESSAGE = ` pull-prebuilt-wasm-artifacts Usage: - npm run pull:wasm [config] [buildID] [help|h] + npm run pull:wasm [run] [options] - node ./pull-prebuilt-wasm-artifacts [config] [buildID] [help|h] + node ./pull-prebuilt-wasm-artifacts [run] [options] + Run can be specified in one of the following ways: + action_run_id + PR number + branch name (default: "main") - config optional, "release"(default) or "debug" - buildID optional, if not specified, use latest main branch, otherwise a number for a specified build ID - help|h print this message and exit +Options: + -d --debug specify the debug build type of the artifacts to download. + -l --latest if set, will always use the latest build, even if it is not completed yet. + --webgpu-ep if set, will use the webgpu EP wasm build instead of the default(JSEP) one. + -h --help print this message and exit `; -const argv = process.argv.slice(2); +const args = minimist(process.argv.slice(2), { + alias: { + debug: ['d'], + help: ['h'], + latest: ['l'], + }, +}); -if ( - argv.indexOf('--help') !== -1 || - argv.indexOf('-h') !== -1 || - argv.indexOf('help') !== -1 || - argv.indexOf('h') !== -1 -) { +if (args.help || args.h) { console.log(HELP_MESSAGE); process.exit(); } -const arg0isConfig = argv[0] === 'debug' || argv[0] === 'release'; -const arg0isInteger = !arg0isConfig && !isNaN(parseInt(argv[0], 10)); -const config = arg0isConfig ? argv[0] : 'release'; -const buildId = arg0isInteger ? argv[0] : (argv[1] ?? ''); +// Check if GitHub CLI (gh) is installed and available in PATH +try { + execSync('gh --version', { stdio: 'pipe' }).toString().trim(); +} catch (e) { + console.error('Error: GitHub CLI (gh) is not installed or not in PATH.'); + console.error('Please install it from https://cli.github.com/ and try again.'); + process.exit(1); +} + +// in NPM script, the args are parsed as: +// npm [npm_command] [npm_flags] -- [user_flags] +// +// The npm_flags will be parsed and removed by NPM, so they will not be available in process.argv directly. Instead, +// they are available in process.env.npm_config_* variables. +// +// For example, if the user runs the command like this: +// > npm run pull:wasm -- --debug +// In this case, `--debug` will be available in `args.debug` +// +// If the user runs the command like this: +// > npm run pull:wasm --debug +// In this case, `--debug` will be available in `process.env.npm_config_debug`, but not in `args.debug` directly. +// +// The following code checks both the command line arguments and the npm_config_* environment variables to get the correct values. +const debug = args.debug || process.env.npm_config_d || process.env.npm_config_debug; +const latest = args.latest || process.env.npm_config_l || process.env.npm_config_latest; +const webgpuEp = args['webgpu-ep'] || process.env.npm_config_webgpu_ep; + +const folderName = (debug ? 'Debug_wasm' : 'Release_wasm') + (webgpuEp ? '_webgpu' : ''); +const allowImcomplete = latest; -const folderName = config === 'release' ? 'Release_wasm' : 'Debug_wasm'; +const run = args._[0]; // The first non-option argument -function downloadJson(url: string, onSuccess: (data: any) => void) { - https.get(url, (res) => { - const { statusCode } = res; - const contentType = res.headers['content-type']; +const GITHUB_ACTION_REQUEST_OPTIONS = { + headers: { + 'user-agent': 'onnxruntime-web artifact pull', + accept: 'application/vnd.github+json', + 'X-GitHub-Api-Version': '2022-11-28', + }, +}; - if (statusCode !== 200) { - throw new Error(`Failed to download build list. HTTP status code = ${statusCode}`); - } - if (!contentType || !/^application\/json/.test(contentType)) { - throw new Error(`unexpected content type: ${contentType}`); - } - res.setEncoding('utf8'); - let rawData = ''; - res.on('data', (chunk) => { - rawData += chunk; - }); - res.on('end', () => { - onSuccess(JSON.parse(rawData)); - }); +async function downloadJson(url: string): Promise { + return new Promise((resolve, reject) => { + https + .get(url, GITHUB_ACTION_REQUEST_OPTIONS, (res) => { + const { statusCode } = res; + const contentType = res.headers['content-type']; + + if (!statusCode) { + reject(new Error('No response statud code from server.')); + return; + } + if (statusCode >= 400 && statusCode < 500) { + resolve(null); + return; + } else if (statusCode !== 200) { + reject(new Error(`Failed to download build list. HTTP status code = ${statusCode}`)); + return; + } + if (!contentType || !/^application\/json/.test(contentType)) { + reject(new Error(`unexpected content type: ${contentType}`)); + return; + } + res.setEncoding('utf8'); + let rawData = ''; + res.on('data', (chunk) => { + rawData += chunk; + }); + res.on('end', () => { + try { + resolve(JSON.parse(rawData)); + } catch (e) { + reject(e); + } + }); + res.on('error', (err) => { + reject(err); + }); + }) + .on('error', (err) => { + reject(err); + }); }); } -function downloadZip(url: string, onSuccess: (data: Buffer) => void) { - https.get(url, (res) => { - const { statusCode } = res; - const contentType = res.headers['content-type']; +async function downloadArtifactsForRun(run: any): Promise { + const data = await downloadJson(run.artifacts_url); - if (statusCode !== 200) { - throw new Error(`Failed to download build list. HTTP status code = ${statusCode}`); - } - if (!contentType || !/^application\/zip/.test(contentType)) { - throw new Error(`unexpected content type: ${contentType}`); + for (const v of data.artifacts) { + if (v.name === folderName && !v.expired) { + console.log(`=== Ready to download artifacts "${folderName}" from run: ${run.id} ===`); + + const WASM_FOLDER = path.join(__dirname, '../dist'); + if (!fs.existsSync(WASM_FOLDER)) { + fs.mkdirSync(WASM_FOLDER); + } else { + const filesToDelete = ['ort-wasm-simd-threaded.jsep.mjs', 'ort-wasm-simd-threaded.jsep.wasm']; + if (!folderName.endsWith('_webgpu')) { + filesToDelete.push('ort-wasm-simd-threaded.mjs', 'ort-wasm-simd-threaded.wasm'); + } + fs.readdirSync(WASM_FOLDER).forEach((file) => { + if (filesToDelete.includes(file)) { + const filePath = path.join(WASM_FOLDER, file); + console.log(`Deleting old file: ${filePath}`); + fs.unlinkSync(filePath); + } + }); + } + + execSync(`gh run download ${run.id} -n ${folderName} -D "${WASM_FOLDER}" -R Microsoft/onnxruntime`); + + return; } + } - const chunks: Buffer[] = []; - res.on('data', (chunk) => { - chunks.push(chunk); - }); - res.on('end', () => { - onSuccess(Buffer.concat(chunks)); - }); - }); + throw new Error(`No artifact "${folderName}" found for the specified build.`); } -function extractFile(zip: jszip, folder: string, file: string, artifactName: string) { - zip - .file(`${artifactName}/${file}`)! - .nodeStream() - .pipe(fs.createWriteStream(path.join(folder, file))) - .on('finish', () => { - console.log('# file downloaded and extracted: ' + file); - }); -} +async function main() { + // Bootstrap global-agent to honor the proxy settings in + // environment variables, e.g. GLOBAL_AGENT_HTTPS_PROXY. + // See https://github.com/gajus/global-agent/blob/v3.0.0/README.md#environment-variables for details. + globalAgentBootstrap(); + + console.log( + `=== Start to pull WebAssembly artifacts "${folderName}" from CI for ${run ? `Run: "${run}"` : 'main branch'} ===`, + ); + + let sha: string | undefined; + + // If param `run` is specified, we try to figure out what it is. + if (!run) { + // API reference: https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#list-workflow-runs-for-a-workflow + const mainRunData = await downloadJson( + `https://api.github.com/repos/Microsoft/onnxruntime/actions/workflows/152051496/runs?branch=main${allowImcomplete ? '' : '&status=completed'}&per_page=1&exclude_pull_requests=1`, + ); + if (mainRunData.workflow_runs.length === 0) { + throw new Error('No build found'); + } + const run = mainRunData.workflow_runs[0]; + await downloadArtifactsForRun(run); + } else { + // If `run` is a number, it is a run ID or PR number + const runId = parseInt(run, 10); + // check if runId only contains digits + const isRunIdDigitsOnly = /^\d+$/.test(run); + if (isRunIdDigitsOnly && !isNaN(runId)) { + // Try to treat it as a run ID + console.log(' # Trying to treat it as a run ID: ' + runId); + const runData = await downloadJson(`https://api.github.com/repos/Microsoft/onnxruntime/actions/runs/${runId}`); + if (runData) { + console.log(`=== Found run: ${runId} ===`); + await downloadArtifactsForRun(runData); + return; + } + + // If not found, try to treat it as a PR number + console.log(` # Run ID ${runId} not found or not accessible.`); + + // API reference: https://docs.github.com/en/rest/pulls/pulls?apiVersion=2022-11-28#get-a-pull-request + const prData = await downloadJson(`https://api.github.com/repos/Microsoft/onnxruntime/pulls/${runId}`); + sha = prData?.head?.sha; + } + + if (sha) { + console.log(` # Found PR #${run} with SHA: ${sha}`); + } else { + // Try to treat the run parameter as a branch name or commit SHA + console.log(` # Trying to treat "${run}" as a branch name`); -console.log( - `=== Start to pull ${config} WebAssembly artifacts from CI for ${ - buildId ? `build "${buildId}"` : 'latest "main" branch' - } ===`, -); - -// Bootstrap global-agent to honor the proxy settings in -// environment variables, e.g. GLOBAL_AGENT_HTTPS_PROXY. -// See https://github.com/gajus/global-agent/blob/v3.0.0/README.md#environment-variables for details. -globalAgentBootstrap(); - -const filter = buildId - ? `&buildIds=${buildId}` - : '&definitions=161' + - '&resultFilter=succeeded%2CpartiallySucceeded' + - '&$top=1' + - '&repositoryId=Microsoft/onnxruntime' + - '&repositoryType=GitHub' + - '&branchName=refs/heads/main'; - -// API reference: https://docs.microsoft.com/en-us/rest/api/azure/devops/build/builds/list -downloadJson( - `https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/builds?api-version=6.1-preview.6${filter}`, - (data) => { - const buildId = data.value[0].id; - - console.log(`=== Found latest build on main branch: ${buildId} ===`); - - // API reference: https://docs.microsoft.com/en-us/rest/api/azure/devops/build/artifacts/get%20artifact - downloadJson( - `https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/builds/${buildId}/artifacts?api-version=6.1-preview.5`, - (data) => { - let zipLink; - for (const v of data.value) { - if (v.name === folderName) { - zipLink = v.resource.downloadUrl; + // First, try as a branch name + const branchData = await downloadJson( + `https://api.github.com/repos/Microsoft/onnxruntime/branches/${encodeURIComponent(run)}`, + ); + if (branchData) { + sha = branchData.commit.sha; + console.log(` # Found branch "${run}" with SHA: ${sha}`); + } else { + const isPossibleSha = /^[0-9a-f]{7,40}$/.test(`${run}`.trim()); + if (isPossibleSha) { + // If not a branch, try as a commit SHA (works with both full and short SHA) + console.log(` # Trying to treat "${run}" as a commit SHA`); + const commitData = await downloadJson( + `https://api.github.com/repos/Microsoft/onnxruntime/commits/${encodeURIComponent(run)}`, + ); + if (commitData) { + sha = commitData.sha; + console.log(` # Found commit with full SHA: ${sha}`); } } + } - console.log('=== Ready to download zip files ==='); + if (!sha) { + throw new Error(`Could not identify "${run}" as a run ID, PR number, branch name, or commit SHA`); + } + } - const WASM_FOLDER = path.join(__dirname, '../dist'); - if (!fs.existsSync(WASM_FOLDER)) { - fs.mkdirSync(WASM_FOLDER); - } - downloadZip(zipLink, (buffer) => { - void jszip.loadAsync(buffer).then((zip) => { - extractFile(zip, WASM_FOLDER, 'ort-wasm-simd-threaded.wasm', folderName); - extractFile(zip, WASM_FOLDER, 'ort-wasm-simd-threaded.jsep.wasm', folderName); - - extractFile(zip, WASM_FOLDER, 'ort-wasm-simd-threaded.mjs', folderName); - extractFile(zip, WASM_FOLDER, 'ort-wasm-simd-threaded.jsep.mjs', folderName); - }); - }); - }, + // Now that we have the SHA, query for workflow runs associated with this SHA + const workflowRunsData = await downloadJson( + `https://api.github.com/repos/Microsoft/onnxruntime/actions/workflows/152051496/runs?head_sha=${sha}`, ); - }, -); + + if (!workflowRunsData || workflowRunsData.workflow_runs.length === 0) { + throw new Error(`No Web CI workflow runs found for SHA: ${sha}`); + } + + // Get the latest run + const latestRun = workflowRunsData.workflow_runs[0]; + console.log(`=== Found run for SHA ${sha}: ${latestRun.html_url} ===`); + + // Download artifacts from this run + await downloadArtifactsForRun(latestRun); + } +} + +void main(); diff --git a/js/web/test/data/ops/conv-transpose.jsonc b/js/web/test/data/ops/conv-transpose.jsonc index 6429845d23df9..008d58530ee36 100644 --- a/js/web/test/data/ops/conv-transpose.jsonc +++ b/js/web/test/data/ops/conv-transpose.jsonc @@ -348,6 +348,128 @@ } ] }, + { + "name": "ConvTranspose NHWC- group - A", + "operator": "ConvTranspose", + "inputShapeDefinitions": "rankOnly", + "opset": { "domain": "", "version": 17 }, + "attributes": [ + { "name": "kernel_shape", "data": [1, 1], "type": "ints" }, + { "name": "group", "data": 2, "type": "int" } + ], + "cases": [ + { + "name": "T[0]", + "inputs": [ + { + "data": [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 18.0, 20.0, 22.0, 24.0, 26.0, 28.0, 30.0, 32.0, 34.0], + "dims": [1, 2, 3, 3], + "type": "float32" + }, + { + "data": [1.0, 2.0], + "dims": [2, 1, 1, 1], + "type": "float32" + } + ], + "outputs": [ + { + "data": [0, 1, 2, 3, 4, 5, 6, 7, 8, 36, 40, 44, 48, 52, 56, 60, 64, 68], + "dims": [1, 2, 3, 3], + "type": "float32" + } + ] + } + ] + }, + { + "name": "ConvTranspose NHWC- group - B", + "operator": "ConvTranspose", + "inputShapeDefinitions": "rankOnly", + "opset": { "domain": "", "version": 17 }, + "attributes": [ + { "name": "kernel_shape", "data": [2, 2], "type": "ints" }, + { "name": "group", "data": 3, "type": "int" } + ], + "cases": [ + { + "name": "T[0]", + "inputs": [ + { + "data": [ + 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, + 19.0, 20.0, 21.0, 22.0, 23.0, 0, 0, 0 + ], + "dims": [1, 3, 3, 3], + "type": "float32" + }, + { + "data": [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0], + "dims": [3, 1, 2, 2], + "type": "float32" + }, + { + "data": [0.125, 0.25, 0.375], + "dims": [3], + "type": "float32" + } + ], + "outputs": [ + { + "data": [ + 0.125, 1.125, 4.125, 4.125, 3.125, 13.125, 23.125, 18.125, 15.125, 43.125, 53.125, 36.125, 18.125, 45.125, + 52.125, 32.125, 45.25, 104.25, 115.25, 66.25, 123.25, 279.25, 305.25, 172.25, 159.25, 357.25, 383.25, + 214.25, 105.25, 232.25, 247.25, 136.25, 162.375, 351.375, 370.375, 200.375, 387.375, 833.375, 875.375, + 470.375, 231.375, 494.375, 517.375, 276.375, 0.375, 0.375, 0.375, 0.375 + ], + "dims": [1, 3, 4, 4], + "type": "float32" + } + ] + } + ] + }, + { + "name": "ConvTranspose NHWC- group - C", + "operator": "ConvTranspose", + "inputShapeDefinitions": "rankOnly", + "opset": { "domain": "", "version": 17 }, + "attributes": [ + { "name": "kernel_shape", "data": [2, 2], "type": "ints" }, + { "name": "group", "data": 3, "type": "int" } + ], + "cases": [ + { + "name": "T[0]", + "inputs": [ + { + "data": [ + 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, + 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0, 32.0, 33.0, 34.0, 35.0 + ], + "dims": [1, 3, 3, 4], + "type": "float32" + }, + { + "data": [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0], + "dims": [3, 1, 2, 2], + "type": "float32" + } + ], + "outputs": [ + { + "data": [ + 0, 1, 4, 7, 6, 4, 16, 26, 36, 26, 20, 56, 66, 76, 50, 24, 59, 66, 73, 44, 60, 137, 148, 159, 90, 164, 368, + 394, 420, 234, 212, 472, 498, 524, 290, 140, 307, 322, 337, 184, 216, 465, 484, 503, 270, 516, 1104, 1146, + 1188, 634, 596, 1272, 1314, 1356, 722, 352, 747, 770, 793, 420 + ], + "dims": [1, 3, 4, 5], + "type": "float32" + } + ] + } + ] + }, { "name": "ConvTranspose with bias addition C", "operator": "ConvTranspose", diff --git a/js/web/test/e2e/exports/main.js b/js/web/test/e2e/exports/main.js index 8ed22a6784e7c..d8c7bbf69039f 100644 --- a/js/web/test/e2e/exports/main.js +++ b/js/web/test/e2e/exports/main.js @@ -3,7 +3,7 @@ 'use strict'; -const { runDevTest, runProdTest } = require('./test'); +const { runDevTest, runProdTest, verifyAssets } = require('./test'); const { installOrtPackages } = require('./utils'); /** @@ -29,5 +29,14 @@ module.exports = async function main(PRESERVE, PACKAGES_TO_INSTALL) { await runDevTest('vite-default', '\x1b[32mâžœ\x1b[39m \x1b[1mLocal\x1b[22m:', 5173); await runProdTest('vite-default', '\x1b[32mâžœ\x1b[39m \x1b[1mLocal\x1b[22m:', 4173); + + await verifyAssets('vite-default', async (cwd) => { + const globby = await import('globby'); + + return { + test: 'File "dist/assets/**/ort.*.mjs" should not exist', + success: globby.globbySync('dist/assets/**/ort.*.mjs', { cwd }).length === 0, + }; + }); } }; diff --git a/js/web/test/e2e/exports/test.js b/js/web/test/e2e/exports/test.js index 9c5ed745ab0b5..e2bcffea97519 100644 --- a/js/web/test/e2e/exports/test.js +++ b/js/web/test/e2e/exports/test.js @@ -121,7 +121,29 @@ async function runProdTest(testCaseName, ready, port) { await runTest(testCaseName, ['prod'], ready, 'npm run start', port); } +async function verifyAssets(testCaseName, testers) { + testers = Array.isArray(testers) ? testers : [testers]; + const wd = path.join(__dirname, 'testcases', testCaseName); + + console.log(`[${testCaseName}] Verifying assets...`); + + const testResults = []; + + try { + for (const tester of testers) { + testResults.push(await tester(wd)); + } + + if (testResults.some((r) => !r.success)) { + throw new Error(`[${testCaseName}] asset verification failed.`); + } + } finally { + console.log(`[${testCaseName}] asset verification result:`, testResults); + } +} + module.exports = { runDevTest, runProdTest, + verifyAssets, }; diff --git a/js/web/test/e2e/exports/testcases/nextjs-default/package-lock.json b/js/web/test/e2e/exports/testcases/nextjs-default/package-lock.json index 174812402f578..6f749319def3d 100644 --- a/js/web/test/e2e/exports/testcases/nextjs-default/package-lock.json +++ b/js/web/test/e2e/exports/testcases/nextjs-default/package-lock.json @@ -8,7 +8,7 @@ "name": "nextjs-default", "version": "0.1.0", "dependencies": { - "next": "15.1.2", + "next": "15.2.4", "react": "^19.0.0", "react-dom": "^19.0.0" } @@ -385,15 +385,15 @@ } }, "node_modules/@next/env": { - "version": "15.1.2", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.1.2.tgz", - "integrity": "sha512-Hm3jIGsoUl6RLB1vzY+dZeqb+/kWPZ+h34yiWxW0dV87l8Im/eMOwpOA+a0L78U0HM04syEjXuRlCozqpwuojQ==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.2.4.tgz", + "integrity": "sha512-+SFtMgoiYP3WoSswuNmxJOCwi06TdWE733D+WPjpXIe4LXGULwEaofiiAy6kbS0+XjM5xF5n3lKuBwN2SnqD9g==", "license": "MIT" }, "node_modules/@next/swc-darwin-arm64": { - "version": "15.1.2", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.1.2.tgz", - "integrity": "sha512-b9TN7q+j5/7+rGLhFAVZiKJGIASuo8tWvInGfAd8wsULjB1uNGRCj1z1WZwwPWzVQbIKWFYqc+9L7W09qwt52w==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.2.4.tgz", + "integrity": "sha512-1AnMfs655ipJEDC/FHkSr0r3lXBgpqKo4K1kiwfUf3iE68rDFXZ1TtHdMvf7D0hMItgDZ7Vuq3JgNMbt/+3bYw==", "cpu": [ "arm64" ], @@ -407,9 +407,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "15.1.2", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.1.2.tgz", - "integrity": "sha512-caR62jNDUCU+qobStO6YJ05p9E+LR0EoXh1EEmyU69cYydsAy7drMcOlUlRtQihM6K6QfvNwJuLhsHcCzNpqtA==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.2.4.tgz", + "integrity": "sha512-3qK2zb5EwCwxnO2HeO+TRqCubeI/NgCe+kL5dTJlPldV/uwCnUgC7VbEzgmxbfrkbjehL4H9BPztWOEtsoMwew==", "cpu": [ "x64" ], @@ -423,9 +423,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.1.2", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.1.2.tgz", - "integrity": "sha512-fHHXBusURjBmN6VBUtu6/5s7cCeEkuGAb/ZZiGHBLVBXMBy4D5QpM8P33Or8JD1nlOjm/ZT9sEE5HouQ0F+hUA==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.2.4.tgz", + "integrity": "sha512-HFN6GKUcrTWvem8AZN7tT95zPb0GUGv9v0d0iyuTb303vbXkkbHDp/DxufB04jNVD+IN9yHy7y/6Mqq0h0YVaQ==", "cpu": [ "arm64" ], @@ -439,9 +439,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.1.2", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.1.2.tgz", - "integrity": "sha512-9CF1Pnivij7+M3G74lxr+e9h6o2YNIe7QtExWq1KUK4hsOLTBv6FJikEwCaC3NeYTflzrm69E5UfwEAbV2U9/g==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.2.4.tgz", + "integrity": "sha512-Oioa0SORWLwi35/kVB8aCk5Uq+5/ZIumMK1kJV+jSdazFm2NzPDztsefzdmzzpx5oGCJ6FkUC7vkaUseNTStNA==", "cpu": [ "arm64" ], @@ -455,9 +455,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.1.2", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.1.2.tgz", - "integrity": "sha512-tINV7WmcTUf4oM/eN3Yuu/f8jQ5C6AkueZPKeALs/qfdfX57eNv4Ij7rt0SA6iZ8+fMobVfcFVv664Op0caCCg==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.2.4.tgz", + "integrity": "sha512-yb5WTRaHdkgOqFOZiu6rHV1fAEK0flVpaIN2HB6kxHVSy/dIajWbThS7qON3W9/SNOH2JWkVCyulgGYekMePuw==", "cpu": [ "x64" ], @@ -471,9 +471,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "15.1.2", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.1.2.tgz", - "integrity": "sha512-jf2IseC4WRsGkzeUw/cK3wci9pxR53GlLAt30+y+B+2qAQxMw6WAC3QrANIKxkcoPU3JFh/10uFfmoMDF9JXKg==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.2.4.tgz", + "integrity": "sha512-Dcdv/ix6srhkM25fgXiyOieFUkz+fOYkHlydWCtB0xMST6X9XYI3yPDKBZt1xuhOytONsIFJFB08xXYsxUwJLw==", "cpu": [ "x64" ], @@ -487,9 +487,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.1.2", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.1.2.tgz", - "integrity": "sha512-wvg7MlfnaociP7k8lxLX4s2iBJm4BrNiNFhVUY+Yur5yhAJHfkS8qPPeDEUH8rQiY0PX3u/P7Q/wcg6Mv6GSAA==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.2.4.tgz", + "integrity": "sha512-dW0i7eukvDxtIhCYkMrZNQfNicPDExt2jPb9AZPpL7cfyUo7QSNl1DjsHjmmKp6qNAqUESyT8YFl/Aw91cNJJg==", "cpu": [ "arm64" ], @@ -503,9 +503,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.1.2", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.1.2.tgz", - "integrity": "sha512-D3cNA8NoT3aWISWmo7HF5Eyko/0OdOO+VagkoJuiTk7pyX3P/b+n8XA/MYvyR+xSVcbKn68B1rY9fgqjNISqzQ==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.2.4.tgz", + "integrity": "sha512-SbnWkJmkS7Xl3kre8SdMF6F/XDh1DTFEhp0jRTj/uB8iPKoU2bb2NDfcu+iifv1+mxQEd1g2vvSxcZbXSKyWiQ==", "cpu": [ "x64" ], @@ -651,12 +651,12 @@ } }, "node_modules/next": { - "version": "15.1.2", - "resolved": "https://registry.npmjs.org/next/-/next-15.1.2.tgz", - "integrity": "sha512-nLJDV7peNy+0oHlmY2JZjzMfJ8Aj0/dd3jCwSZS8ZiO5nkQfcZRqDrRN3U5rJtqVTQneIOGZzb6LCNrk7trMCQ==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/next/-/next-15.2.4.tgz", + "integrity": "sha512-VwL+LAaPSxEkd3lU2xWbgEOtrM8oedmyhBqaVNmgKB+GvZlCy9rgaEc+y2on0wv+l0oSFqLtYD6dcC1eAedUaQ==", "license": "MIT", "dependencies": { - "@next/env": "15.1.2", + "@next/env": "15.2.4", "@swc/counter": "0.1.3", "@swc/helpers": "0.5.15", "busboy": "1.6.0", @@ -671,14 +671,14 @@ "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "15.1.2", - "@next/swc-darwin-x64": "15.1.2", - "@next/swc-linux-arm64-gnu": "15.1.2", - "@next/swc-linux-arm64-musl": "15.1.2", - "@next/swc-linux-x64-gnu": "15.1.2", - "@next/swc-linux-x64-musl": "15.1.2", - "@next/swc-win32-arm64-msvc": "15.1.2", - "@next/swc-win32-x64-msvc": "15.1.2", + "@next/swc-darwin-arm64": "15.2.4", + "@next/swc-darwin-x64": "15.2.4", + "@next/swc-linux-arm64-gnu": "15.2.4", + "@next/swc-linux-arm64-musl": "15.2.4", + "@next/swc-linux-x64-gnu": "15.2.4", + "@next/swc-linux-x64-musl": "15.2.4", + "@next/swc-win32-arm64-msvc": "15.2.4", + "@next/swc-win32-x64-msvc": "15.2.4", "sharp": "^0.33.5" }, "peerDependencies": { diff --git a/js/web/test/e2e/exports/testcases/nextjs-default/package.json b/js/web/test/e2e/exports/testcases/nextjs-default/package.json index 6688445cded26..297b4b56e9bb7 100644 --- a/js/web/test/e2e/exports/testcases/nextjs-default/package.json +++ b/js/web/test/e2e/exports/testcases/nextjs-default/package.json @@ -11,6 +11,6 @@ "dependencies": { "react": "^19.0.0", "react-dom": "^19.0.0", - "next": "15.1.2" + "next": "15.2.4" } } diff --git a/js/web/test/e2e/exports/testcases/vite-default/package-lock.json b/js/web/test/e2e/exports/testcases/vite-default/package-lock.json index 891b40710ff99..708e458748b3a 100644 --- a/js/web/test/e2e/exports/testcases/vite-default/package-lock.json +++ b/js/web/test/e2e/exports/testcases/vite-default/package-lock.json @@ -12,7 +12,7 @@ }, "devDependencies": { "@vitejs/plugin-vue": "^5.2.1", - "vite": "^6.0.11" + "vite": "^6.2.5" } }, "node_modules/@babel/helper-string-parser": { @@ -62,9 +62,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", - "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", + "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==", "cpu": [ "ppc64" ], @@ -79,9 +79,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", - "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz", + "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==", "cpu": [ "arm" ], @@ -96,9 +96,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", - "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz", + "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==", "cpu": [ "arm64" ], @@ -113,9 +113,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", - "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz", + "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==", "cpu": [ "x64" ], @@ -130,9 +130,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", - "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", + "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", "cpu": [ "arm64" ], @@ -147,9 +147,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", - "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz", + "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==", "cpu": [ "x64" ], @@ -164,9 +164,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", - "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz", + "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==", "cpu": [ "arm64" ], @@ -181,9 +181,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", - "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz", + "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==", "cpu": [ "x64" ], @@ -198,9 +198,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", - "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz", + "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==", "cpu": [ "arm" ], @@ -215,9 +215,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", - "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz", + "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==", "cpu": [ "arm64" ], @@ -232,9 +232,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", - "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz", + "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==", "cpu": [ "ia32" ], @@ -249,9 +249,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", - "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz", + "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==", "cpu": [ "loong64" ], @@ -266,9 +266,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", - "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz", + "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==", "cpu": [ "mips64el" ], @@ -283,9 +283,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", - "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz", + "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==", "cpu": [ "ppc64" ], @@ -300,9 +300,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", - "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", + "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", "cpu": [ "riscv64" ], @@ -317,9 +317,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", - "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", + "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", "cpu": [ "s390x" ], @@ -334,9 +334,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", - "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", + "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", "cpu": [ "x64" ], @@ -351,9 +351,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", - "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz", + "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==", "cpu": [ "arm64" ], @@ -368,9 +368,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", - "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz", + "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==", "cpu": [ "x64" ], @@ -385,9 +385,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", - "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz", + "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==", "cpu": [ "arm64" ], @@ -402,9 +402,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", - "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz", + "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==", "cpu": [ "x64" ], @@ -419,9 +419,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", - "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz", + "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==", "cpu": [ "x64" ], @@ -436,9 +436,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", - "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz", + "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==", "cpu": [ "arm64" ], @@ -453,9 +453,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", - "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz", + "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==", "cpu": [ "ia32" ], @@ -470,9 +470,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", - "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz", + "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==", "cpu": [ "x64" ], @@ -493,9 +493,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.29.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.29.2.tgz", - "integrity": "sha512-s/8RiF4bdmGnc/J0N7lHAr5ZFJj+NdJqJ/Hj29K+c4lEdoVlukzvWXB9XpWZCdakVT0YAw8iyIqUP2iFRz5/jA==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.35.0.tgz", + "integrity": "sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ==", "cpu": [ "arm" ], @@ -507,9 +507,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.29.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.29.2.tgz", - "integrity": "sha512-mKRlVj1KsKWyEOwR6nwpmzakq6SgZXW4NUHNWlYSiyncJpuXk7wdLzuKdWsRoR1WLbWsZBKvsUCdCTIAqRn9cA==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.35.0.tgz", + "integrity": "sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA==", "cpu": [ "arm64" ], @@ -521,9 +521,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.29.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.29.2.tgz", - "integrity": "sha512-vJX+vennGwygmutk7N333lvQ/yKVAHnGoBS2xMRQgXWW8tvn46YWuTDOpKroSPR9BEW0Gqdga2DHqz8Pwk6X5w==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.35.0.tgz", + "integrity": "sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q==", "cpu": [ "arm64" ], @@ -535,9 +535,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.29.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.29.2.tgz", - "integrity": "sha512-e2rW9ng5O6+Mt3ht8fH0ljfjgSCC6ffmOipiLUgAnlK86CHIaiCdHCzHzmTkMj6vEkqAiRJ7ss6Ibn56B+RE5w==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.35.0.tgz", + "integrity": "sha512-3IrHjfAS6Vkp+5bISNQnPogRAW5GAV1n+bNCrDwXmfMHbPl5EhTmWtfmwlJxFRUCBZ+tZ/OxDyU08aF6NI/N5Q==", "cpu": [ "x64" ], @@ -549,9 +549,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.29.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.29.2.tgz", - "integrity": "sha512-/xdNwZe+KesG6XJCK043EjEDZTacCtL4yurMZRLESIgHQdvtNyul3iz2Ab03ZJG0pQKbFTu681i+4ETMF9uE/Q==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.35.0.tgz", + "integrity": "sha512-sxjoD/6F9cDLSELuLNnY0fOrM9WA0KrM0vWm57XhrIMf5FGiN8D0l7fn+bpUeBSU7dCgPV2oX4zHAsAXyHFGcQ==", "cpu": [ "arm64" ], @@ -563,9 +563,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.29.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.29.2.tgz", - "integrity": "sha512-eXKvpThGzREuAbc6qxnArHh8l8W4AyTcL8IfEnmx+bcnmaSGgjyAHbzZvHZI2csJ+e0MYddl7DX0X7g3sAuXDQ==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.35.0.tgz", + "integrity": "sha512-2mpHCeRuD1u/2kruUiHSsnjWtHjqVbzhBkNVQ1aVD63CcexKVcQGwJ2g5VphOd84GvxfSvnnlEyBtQCE5hxVVw==", "cpu": [ "x64" ], @@ -577,9 +577,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.29.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.29.2.tgz", - "integrity": "sha512-h4VgxxmzmtXLLYNDaUcQevCmPYX6zSj4SwKuzY7SR5YlnCBYsmvfYORXgiU8axhkFCDtQF3RW5LIXT8B14Qykg==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.35.0.tgz", + "integrity": "sha512-mrA0v3QMy6ZSvEuLs0dMxcO2LnaCONs1Z73GUDBHWbY8tFFocM6yl7YyMu7rz4zS81NDSqhrUuolyZXGi8TEqg==", "cpu": [ "arm" ], @@ -591,9 +591,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.29.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.29.2.tgz", - "integrity": "sha512-EObwZ45eMmWZQ1w4N7qy4+G1lKHm6mcOwDa+P2+61qxWu1PtQJ/lz2CNJ7W3CkfgN0FQ7cBUy2tk6D5yR4KeXw==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.35.0.tgz", + "integrity": "sha512-DnYhhzcvTAKNexIql8pFajr0PiDGrIsBYPRvCKlA5ixSS3uwo/CWNZxB09jhIapEIg945KOzcYEAGGSmTSpk7A==", "cpu": [ "arm" ], @@ -605,9 +605,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.29.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.29.2.tgz", - "integrity": "sha512-Z7zXVHEXg1elbbYiP/29pPwlJtLeXzjrj4241/kCcECds8Zg9fDfURWbZHRIKrEriAPS8wnVtdl4ZJBvZr325w==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.35.0.tgz", + "integrity": "sha512-uagpnH2M2g2b5iLsCTZ35CL1FgyuzzJQ8L9VtlJ+FckBXroTwNOaD0z0/UF+k5K3aNQjbm8LIVpxykUOQt1m/A==", "cpu": [ "arm64" ], @@ -619,9 +619,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.29.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.29.2.tgz", - "integrity": "sha512-TF4kxkPq+SudS/r4zGPf0G08Bl7+NZcFrUSR3484WwsHgGgJyPQRLCNrQ/R5J6VzxfEeQR9XRpc8m2t7lD6SEQ==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.35.0.tgz", + "integrity": "sha512-XQxVOCd6VJeHQA/7YcqyV0/88N6ysSVzRjJ9I9UA/xXpEsjvAgDTgH3wQYz5bmr7SPtVK2TsP2fQ2N9L4ukoUg==", "cpu": [ "arm64" ], @@ -633,9 +633,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.29.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.29.2.tgz", - "integrity": "sha512-kO9Fv5zZuyj2zB2af4KA29QF6t7YSxKrY7sxZXfw8koDQj9bx5Tk5RjH+kWKFKok0wLGTi4bG117h31N+TIBEg==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.35.0.tgz", + "integrity": "sha512-5pMT5PzfgwcXEwOaSrqVsz/LvjDZt+vQ8RT/70yhPU06PTuq8WaHhfT1LW+cdD7mW6i/J5/XIkX/1tCAkh1W6g==", "cpu": [ "loong64" ], @@ -647,9 +647,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.29.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.29.2.tgz", - "integrity": "sha512-gIh776X7UCBaetVJGdjXPFurGsdWwHHinwRnC5JlLADU8Yk0EdS/Y+dMO264OjJFo7MXQ5PX4xVFbxrwK8zLqA==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.35.0.tgz", + "integrity": "sha512-c+zkcvbhbXF98f4CtEIP1EBA/lCic5xB0lToneZYvMeKu5Kamq3O8gqrxiYYLzlZH6E3Aq+TSW86E4ay8iD8EA==", "cpu": [ "ppc64" ], @@ -661,9 +661,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.29.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.29.2.tgz", - "integrity": "sha512-YgikssQ5UNq1GoFKZydMEkhKbjlUq7G3h8j6yWXLBF24KyoA5BcMtaOUAXq5sydPmOPEqB6kCyJpyifSpCfQ0w==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.35.0.tgz", + "integrity": "sha512-s91fuAHdOwH/Tad2tzTtPX7UZyytHIRR6V4+2IGlV0Cej5rkG0R61SX4l4y9sh0JBibMiploZx3oHKPnQBKe4g==", "cpu": [ "riscv64" ], @@ -675,9 +675,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.29.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.29.2.tgz", - "integrity": "sha512-9ouIR2vFWCyL0Z50dfnon5nOrpDdkTG9lNDs7MRaienQKlTyHcDxplmk3IbhFlutpifBSBr2H4rVILwmMLcaMA==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.35.0.tgz", + "integrity": "sha512-hQRkPQPLYJZYGP+Hj4fR9dDBMIM7zrzJDWFEMPdTnTy95Ljnv0/4w/ixFw3pTBMEuuEuoqtBINYND4M7ujcuQw==", "cpu": [ "s390x" ], @@ -689,9 +689,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.29.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.29.2.tgz", - "integrity": "sha512-ckBBNRN/F+NoSUDENDIJ2U9UWmIODgwDB/vEXCPOMcsco1niTkxTXa6D2Y/pvCnpzaidvY2qVxGzLilNs9BSzw==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.35.0.tgz", + "integrity": "sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA==", "cpu": [ "x64" ], @@ -703,9 +703,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.29.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.29.2.tgz", - "integrity": "sha512-jycl1wL4AgM2aBFJFlpll/kGvAjhK8GSbEmFT5v3KC3rP/b5xZ1KQmv0vQQ8Bzb2ieFQ0kZFPRMbre/l3Bu9JA==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.35.0.tgz", + "integrity": "sha512-QysqXzYiDvQWfUiTm8XmJNO2zm9yC9P/2Gkrwg2dH9cxotQzunBHYr6jk4SujCTqnfGxduOmQcI7c2ryuW8XVg==", "cpu": [ "x64" ], @@ -717,9 +717,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.29.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.29.2.tgz", - "integrity": "sha512-S2V0LlcOiYkNGlRAWZwwUdNgdZBfvsDHW0wYosYFV3c7aKgEVcbonetZXsHv7jRTTX+oY5nDYT4W6B1oUpMNOg==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.35.0.tgz", + "integrity": "sha512-OUOlGqPkVJCdJETKOCEf1mw848ZyJ5w50/rZ/3IBQVdLfR5jk/6Sr5m3iO2tdPgwo0x7VcncYuOvMhBWZq8ayg==", "cpu": [ "arm64" ], @@ -731,9 +731,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.29.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.29.2.tgz", - "integrity": "sha512-pW8kioj9H5f/UujdoX2atFlXNQ9aCfAxFRaa+mhczwcsusm6gGrSo4z0SLvqLF5LwFqFTjiLCCzGkNK/LE0utQ==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.35.0.tgz", + "integrity": "sha512-2/lsgejMrtwQe44glq7AFFHLfJBPafpsTa6JvP2NGef/ifOa4KBoglVf7AKN7EV9o32evBPRqfg96fEHzWo5kw==", "cpu": [ "ia32" ], @@ -745,9 +745,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.29.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.29.2.tgz", - "integrity": "sha512-p6fTArexECPf6KnOHvJXRpAEq0ON1CBtzG/EY4zw08kCHk/kivBc5vUEtnCFNCHOpJZ2ne77fxwRLIKD4wuW2Q==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.35.0.tgz", + "integrity": "sha512-PIQeY5XDkrOysbQblSW7v3l1MDZzkTEzAfTPkj5VAu3FW8fS4ynyLg2sINp0fp3SjZ8xkRYpLqoKcYqAkhU1dw==", "cpu": [ "x64" ], @@ -898,9 +898,9 @@ } }, "node_modules/esbuild": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", - "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", + "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -911,31 +911,31 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.24.2", - "@esbuild/android-arm": "0.24.2", - "@esbuild/android-arm64": "0.24.2", - "@esbuild/android-x64": "0.24.2", - "@esbuild/darwin-arm64": "0.24.2", - "@esbuild/darwin-x64": "0.24.2", - "@esbuild/freebsd-arm64": "0.24.2", - "@esbuild/freebsd-x64": "0.24.2", - "@esbuild/linux-arm": "0.24.2", - "@esbuild/linux-arm64": "0.24.2", - "@esbuild/linux-ia32": "0.24.2", - "@esbuild/linux-loong64": "0.24.2", - "@esbuild/linux-mips64el": "0.24.2", - "@esbuild/linux-ppc64": "0.24.2", - "@esbuild/linux-riscv64": "0.24.2", - "@esbuild/linux-s390x": "0.24.2", - "@esbuild/linux-x64": "0.24.2", - "@esbuild/netbsd-arm64": "0.24.2", - "@esbuild/netbsd-x64": "0.24.2", - "@esbuild/openbsd-arm64": "0.24.2", - "@esbuild/openbsd-x64": "0.24.2", - "@esbuild/sunos-x64": "0.24.2", - "@esbuild/win32-arm64": "0.24.2", - "@esbuild/win32-ia32": "0.24.2", - "@esbuild/win32-x64": "0.24.2" + "@esbuild/aix-ppc64": "0.25.1", + "@esbuild/android-arm": "0.25.1", + "@esbuild/android-arm64": "0.25.1", + "@esbuild/android-x64": "0.25.1", + "@esbuild/darwin-arm64": "0.25.1", + "@esbuild/darwin-x64": "0.25.1", + "@esbuild/freebsd-arm64": "0.25.1", + "@esbuild/freebsd-x64": "0.25.1", + "@esbuild/linux-arm": "0.25.1", + "@esbuild/linux-arm64": "0.25.1", + "@esbuild/linux-ia32": "0.25.1", + "@esbuild/linux-loong64": "0.25.1", + "@esbuild/linux-mips64el": "0.25.1", + "@esbuild/linux-ppc64": "0.25.1", + "@esbuild/linux-riscv64": "0.25.1", + "@esbuild/linux-s390x": "0.25.1", + "@esbuild/linux-x64": "0.25.1", + "@esbuild/netbsd-arm64": "0.25.1", + "@esbuild/netbsd-x64": "0.25.1", + "@esbuild/openbsd-arm64": "0.25.1", + "@esbuild/openbsd-x64": "0.25.1", + "@esbuild/sunos-x64": "0.25.1", + "@esbuild/win32-arm64": "0.25.1", + "@esbuild/win32-ia32": "0.25.1", + "@esbuild/win32-x64": "0.25.1" } }, "node_modules/estree-walker": { @@ -993,9 +993,9 @@ "license": "ISC" }, "node_modules/postcss": { - "version": "8.4.49", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", - "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", "funding": [ { "type": "opencollective", @@ -1012,7 +1012,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", + "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -1021,9 +1021,9 @@ } }, "node_modules/rollup": { - "version": "4.29.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.29.2.tgz", - "integrity": "sha512-tJXpsEkzsEzyAKIaB3qv3IuvTVcTN7qBw1jL4SPPXM3vzDrJgiLGFY6+HodgFaUHAJ2RYJ94zV5MKRJCoQzQeA==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.35.0.tgz", + "integrity": "sha512-kg6oI4g+vc41vePJyO6dHt/yl0Rz3Thv0kJeVQ3D1kS3E5XSuKbPc29G4IpT/Kv1KQwgHVcN+HtyS+HYLNSvQg==", "dev": true, "license": "MIT", "dependencies": { @@ -1037,25 +1037,25 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.29.2", - "@rollup/rollup-android-arm64": "4.29.2", - "@rollup/rollup-darwin-arm64": "4.29.2", - "@rollup/rollup-darwin-x64": "4.29.2", - "@rollup/rollup-freebsd-arm64": "4.29.2", - "@rollup/rollup-freebsd-x64": "4.29.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.29.2", - "@rollup/rollup-linux-arm-musleabihf": "4.29.2", - "@rollup/rollup-linux-arm64-gnu": "4.29.2", - "@rollup/rollup-linux-arm64-musl": "4.29.2", - "@rollup/rollup-linux-loongarch64-gnu": "4.29.2", - "@rollup/rollup-linux-powerpc64le-gnu": "4.29.2", - "@rollup/rollup-linux-riscv64-gnu": "4.29.2", - "@rollup/rollup-linux-s390x-gnu": "4.29.2", - "@rollup/rollup-linux-x64-gnu": "4.29.2", - "@rollup/rollup-linux-x64-musl": "4.29.2", - "@rollup/rollup-win32-arm64-msvc": "4.29.2", - "@rollup/rollup-win32-ia32-msvc": "4.29.2", - "@rollup/rollup-win32-x64-msvc": "4.29.2", + "@rollup/rollup-android-arm-eabi": "4.35.0", + "@rollup/rollup-android-arm64": "4.35.0", + "@rollup/rollup-darwin-arm64": "4.35.0", + "@rollup/rollup-darwin-x64": "4.35.0", + "@rollup/rollup-freebsd-arm64": "4.35.0", + "@rollup/rollup-freebsd-x64": "4.35.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.35.0", + "@rollup/rollup-linux-arm-musleabihf": "4.35.0", + "@rollup/rollup-linux-arm64-gnu": "4.35.0", + "@rollup/rollup-linux-arm64-musl": "4.35.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.35.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.35.0", + "@rollup/rollup-linux-riscv64-gnu": "4.35.0", + "@rollup/rollup-linux-s390x-gnu": "4.35.0", + "@rollup/rollup-linux-x64-gnu": "4.35.0", + "@rollup/rollup-linux-x64-musl": "4.35.0", + "@rollup/rollup-win32-arm64-msvc": "4.35.0", + "@rollup/rollup-win32-ia32-msvc": "4.35.0", + "@rollup/rollup-win32-x64-msvc": "4.35.0", "fsevents": "~2.3.2" } }, @@ -1069,15 +1069,15 @@ } }, "node_modules/vite": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.11.tgz", - "integrity": "sha512-4VL9mQPKoHy4+FE0NnRE/kbY51TOfaknxAjt3fJbGJxhIpBZiqVzlZDEesWWsuREXHwNdAoOFZ9MkPEVXczHwg==", + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.5.tgz", + "integrity": "sha512-j023J/hCAa4pRIUH6J9HemwYfjB5llR2Ps0CWeikOtdR8+pAURAk0DoJC5/mm9kd+UgdnIy7d6HE4EAvlYhPhA==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.24.2", - "postcss": "^8.4.49", - "rollup": "^4.23.0" + "esbuild": "^0.25.0", + "postcss": "^8.5.3", + "rollup": "^4.30.1" }, "bin": { "vite": "bin/vite.js" diff --git a/js/web/test/e2e/exports/testcases/vite-default/package.json b/js/web/test/e2e/exports/testcases/vite-default/package.json index 9e204875a1d01..904db7a41de9c 100644 --- a/js/web/test/e2e/exports/testcases/vite-default/package.json +++ b/js/web/test/e2e/exports/testcases/vite-default/package.json @@ -13,6 +13,6 @@ }, "devDependencies": { "@vitejs/plugin-vue": "^5.2.1", - "vite": "^6.0.11" + "vite": "^6.2.5" } } diff --git a/js/web/test/test-runner.ts b/js/web/test/test-runner.ts index 5de39535a5c07..6fbce114093c0 100644 --- a/js/web/test/test-runner.ts +++ b/js/web/test/test-runner.ts @@ -1016,8 +1016,9 @@ export class ProtoOpTestContext { // check if all test cases have the same shape for each inputs if ( test.cases.some((testCase) => - testCase.inputs!.some((input: Test.TensorValue, i) => - TensorResultValidator.integerEqual(input.dims, (test.cases[0].inputs![i] as Test.TensorValue).dims), + testCase.inputs!.some( + (input: Test.TensorValue, i) => + !TensorResultValidator.integerEqual(input.dims, (test.cases[0].inputs![i] as Test.TensorValue).dims), ), ) ) { diff --git a/js/web/test/unittests/backends/wasm/test-model-metadata.ts b/js/web/test/unittests/backends/wasm/test-model-metadata.ts new file mode 100644 index 0000000000000..9b70686633f27 --- /dev/null +++ b/js/web/test/unittests/backends/wasm/test-model-metadata.ts @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { expect } from 'chai'; +import { InferenceSession } from 'onnxruntime-common'; + +const ONNX_MODEL_TEST_ABS_NO_SHAPE = Uint8Array.from([ + 8, 9, 58, 73, 10, 31, 10, 7, 105, 110, 112, 117, 116, 95, 48, 18, 8, 111, 117, 116, 112, 117, 116, 95, 48, 26, 3, 65, + 98, 115, 34, 3, 65, 98, 115, 58, 0, 18, 3, 97, 98, 115, 90, 15, 10, 7, 105, 110, 112, 117, 116, 95, 48, 18, 4, 10, 2, + 8, 1, 98, 16, 10, 8, 111, 117, 116, 112, 117, 116, 95, 48, 18, 4, 10, 2, 8, 1, 66, 4, 10, 0, 16, 21, +]); + +const ONNX_MODEL_TEST_ABS_SYMBOL = Uint8Array.from([ + 8, 9, 58, 105, 10, 31, 10, 7, 105, 110, 112, 117, 116, 95, 48, 18, 8, 111, 117, 116, 112, 117, 116, 95, 48, 26, 3, 65, + 98, 115, 34, 3, 65, 98, 115, 58, 0, 18, 3, 97, 98, 115, 90, 47, 10, 7, 105, 110, 112, 117, 116, 95, 48, 18, 36, 10, + 34, 8, 1, 18, 30, 10, 13, 18, 11, 95, 105, 110, 112, 117, 116, 95, 48, 95, 100, 48, 10, 13, 18, 11, 95, 105, 110, 112, + 117, 116, 95, 48, 95, 100, 49, 98, 16, 10, 8, 111, 117, 116, 112, 117, 116, 95, 48, 18, 4, 10, 2, 8, 1, 66, 4, 10, 0, + 16, 21, +]); + +const ONNX_MODEL_TEST_ABS_STATIC = Uint8Array.from([ + 8, 9, 58, 83, 10, 31, 10, 7, 105, 110, 112, 117, 116, 95, 48, 18, 8, 111, 117, 116, 112, 117, 116, 95, 48, 26, 3, 65, + 98, 115, 34, 3, 65, 98, 115, 58, 0, 18, 3, 97, 98, 115, 90, 25, 10, 7, 105, 110, 112, 117, 116, 95, 48, 18, 14, 10, + 12, 8, 1, 18, 8, 10, 2, 8, 2, 10, 2, 8, 4, 98, 16, 10, 8, 111, 117, 116, 112, 117, 116, 95, 48, 18, 4, 10, 2, 8, 1, + 66, 4, 10, 0, 16, 21, +]); + +const testModelMetadata = async ( + model: Uint8Array, + expectedInputNames: string[], + expectedOutputNames: string[], + expectedInputMetadata: InferenceSession.ValueMetadata[], + expectedOutputMetadata: InferenceSession.ValueMetadata[], +) => { + const session = await InferenceSession.create(model); + expect(session.inputNames).to.deep.equal(expectedInputNames); + expect(session.outputNames).to.deep.equal(expectedOutputNames); + expect(session.inputMetadata).to.deep.equal(expectedInputMetadata); + expect(session.outputMetadata).to.deep.equal(expectedOutputMetadata); +}; + +describe('#UnitTest# - wasm - test model input/output metadata', () => { + it('model input/output with no shape', async () => { + await testModelMetadata( + ONNX_MODEL_TEST_ABS_NO_SHAPE, + ['input_0'], + ['output_0'], + [{ name: 'input_0', isTensor: true, type: 'float32', shape: [] }], + [{ name: 'output_0', isTensor: true, type: 'float32', shape: [] }], + ); + }); + + it('model input/output with symbol shape', async () => { + await testModelMetadata( + ONNX_MODEL_TEST_ABS_SYMBOL, + ['input_0'], + ['output_0'], + [ + { + name: 'input_0', + isTensor: true, + type: 'float32', + shape: ['_input_0_d0', '_input_0_d1'], + }, + ], + [ + { + name: 'output_0', + isTensor: true, + type: 'float32', + shape: ['_input_0_d0', '_input_0_d1'], + }, + ], + ); + }); + + it('model input/output with static shape', async () => { + await testModelMetadata( + ONNX_MODEL_TEST_ABS_STATIC, + ['input_0'], + ['output_0'], + [{ name: 'input_0', isTensor: true, type: 'float32', shape: [2, 4] }], + [{ name: 'output_0', isTensor: true, type: 'float32', shape: [2, 4] }], + ); + }); +}); diff --git a/js/web/test/unittests/index.ts b/js/web/test/unittests/index.ts index 4a0b155ecc80b..b68681f4977c0 100644 --- a/js/web/test/unittests/index.ts +++ b/js/web/test/unittests/index.ts @@ -11,4 +11,6 @@ if (typeof window !== 'undefined') { require('./backends/webgl/test-matmul-packed'); } +require('./backends/wasm/test-model-metadata'); + require('./opset'); diff --git a/onnxruntime/__init__.py b/onnxruntime/__init__.py index 2d68696347910..1a0ea4ca0434b 100644 --- a/onnxruntime/__init__.py +++ b/onnxruntime/__init__.py @@ -8,7 +8,7 @@ or the `Github project `_. """ -__version__ = "1.21.0" +__version__ = "1.22.0" __author__ = "Microsoft" # we need to do device version validation (for example to check Cuda version for an onnxruntime-training package). diff --git a/onnxruntime/contrib_ops/cpu/bert/attention.cc b/onnxruntime/contrib_ops/cpu/bert/attention.cc index ad14fb8258656..de23444e95778 100644 --- a/onnxruntime/contrib_ops/cpu/bert/attention.cc +++ b/onnxruntime/contrib_ops/cpu/bert/attention.cc @@ -335,7 +335,7 @@ Status Attention::Compute(OpKernelContext* context) const { // Compute the attention score and apply the score to V return ApplyAttention(Q, K, V, mask_index, past, nullptr /* past_key */, nullptr /* past_value */, - output, nullptr /* present_key */, nullptr /* present_value */, + output, nullptr /* present_key */, nullptr /* present_value */, nullptr /* output_qk */, batch_size, sequence_length, sequence_length, parameters.head_size, parameters.v_head_size, parameters.v_hidden_size, attention_bias, context); diff --git a/onnxruntime/contrib_ops/cpu/bert/attention_base.h b/onnxruntime/contrib_ops/cpu/bert/attention_base.h index 05756cd54d842..93d35d39390f5 100644 --- a/onnxruntime/contrib_ops/cpu/bert/attention_base.h +++ b/onnxruntime/contrib_ops/cpu/bert/attention_base.h @@ -7,6 +7,7 @@ #include "core/common/common.h" #include "core/framework/op_kernel.h" #include "contrib_ops/cpu/bert/attention_common.h" +#include "contrib_ops/cpu/bert/attention_parameters.h" namespace onnxruntime { namespace contrib { diff --git a/onnxruntime/contrib_ops/cpu/bert/attention_common.h b/onnxruntime/contrib_ops/cpu/bert/attention_common.h index 97d6cc1ce7d66..243f611da49e1 100644 --- a/onnxruntime/contrib_ops/cpu/bert/attention_common.h +++ b/onnxruntime/contrib_ops/cpu/bert/attention_common.h @@ -49,148 +49,10 @@ enum AttentionKernelType { AttentionKernel_FlashAttention, AttentionKernel_CudnnFlashAttention, AttentionKernel_LeanAttention, + AttentionKernel_DecoderAttention, AttentionKernel_Default }; -// Parameters deduced from node attributes and inputs/outputs. -struct AttentionParameters { - int batch_size; - int sequence_length; - int kv_sequence_length; // input sequence length of K or V - int past_sequence_length; // sequence length in past state of K or V - int total_sequence_length; // total sequence length of K or V - int max_sequence_length; // max sequence length from 4D mask - int input_hidden_size; // first dimension of weights for input projection - int hidden_size; // hidden size of Q or K - int head_size; // hidden size per head of Q or K - int v_hidden_size; // hidden size of V - int v_head_size; // hidden size per head of V - int num_heads; - int rotary_embedding; - bool is_unidirectional; - bool past_present_share_buffer; - bool do_rotary; - bool broadcast_attn_bias_dim_0; - bool broadcast_attn_bias_dim_1; - float mask_filter_value; - float scale; - bool use_tf32; - AttentionMaskType mask_type; - AttentionQkvFormat qkv_format; -}; - -struct DecoderMaskedMultiHeadAttentionParams : AttentionParameters { - int beam_width = 1; - - // Only NeoX style rotary embedding is supported - int rotary_embedding_dim = 0; - int t_step = 0; - - // Whether to use multihead attention(excludes matmul and bias) - bool is_mha = false; - bool is_cross_attention = false; - bool is_packed_qkv = false; - - // Useful to better use global memory bandwidth on certain CUDA architectures. - // Turned off by default for now until we fully understand performance implications - // for all types of workloads. - // Can be turned on by appropriate environment variable (see attention_common.h). - bool kv_data_in_flight = false; - - void* q = nullptr; - void* q_bias = nullptr; - - void* k = nullptr; - void* k_bias = nullptr; - - void* v = nullptr; - void* v_bias = nullptr; - - void* attention_bias = nullptr; - - void* k_cache = nullptr; - void* v_cache = nullptr; - - void* out = nullptr; - void* out_qk = nullptr; - - const int32_t* cache_indir = nullptr; - const int32_t* mask = nullptr; // [B, total_sequence_length] -}; - -// Parameters deduced from node attributes and inputs/outputs. -struct PackedAttentionParameters { - int batch_size; - int sequence_length; - int input_hidden_size; // hidden size of input - int hidden_size; // hidden size of Q or K - int head_size; // hidden size per head of Q or K - int v_hidden_size; // hidden size of V - int v_head_size; // hidden size per head of V - int num_heads; - float scale; - int token_count; - bool broadcast_attn_bias_dim_0; - bool broadcast_attn_bias_dim_1; - bool use_tf32; -}; - -// Parameters deduced from node attributes and inputs/outputs. -struct GroupQueryAttentionParameters { - int batch_size; - int sequence_length; // sequence length of input query, key, value - int seqlen_past_kv_cache; // sequence length of past kv tensor - int seqlen_present_kv_cache; // sequence length of present kv tensor - int total_sequence_length; // maximum total sequence length (past_sequence_length + sequence_length) among keys - int hidden_size; - int num_heads; - int head_size; - int kv_hidden_size; - int kv_num_heads; - int num_splits; // number of splits for splitkv - int rotary_dim; // rotary embedding dimension - bool is_unidirectional; // causal - int local_window_size; - bool kv_share_buffer; - bool is_packed_qkv; - bool is_subsequent_prompt; // indicates whether we have past context and seqlen > 1 - bool is_first_prompt; // indicates whether this is first decoding step - bool do_rotary; - bool rotary_interleaved; - bool use_smooth_softmax; - float scale; - float softcap; - AttentionQkvFormat qkv_format; - AttentionQkvFormat past_kv_format; - int zeros_count; - int* zero_ptr; -}; - -// Parameters for sparse attention. -struct SparseAttentionParameters { - int batch_size; // batch size - int sequence_length; // sequence length of input query, key, value - int hidden_size; // hidden size of query - int num_heads; // number of heads of query - int head_size; // hidden size per head of query, key or value - int kv_hidden_size; // hidden size of key or value - int kv_num_heads; // number of heads of key or value - bool do_rotary; // whether to use rotary embedding - bool rotary_interleaved; // whether to use interleaved rotary embedding - int rotary_dim; // rotary embedding dimension - int sparse_block_size; // block size for sparse attention - int num_sparse_layout; // number of sparse layout - int stride_col_indices; // shape of block_col_indices is [num_sparse_layout, stride_col_indices] - int stride_row_indices; // shape of block_row_indices is [num_sparse_layout, stride_row_indices] - float scale; // scaling factor applied prior to softmax - bool is_packed_qkv; // whether qkv is packed - int total_sequence_length; // maximum total sequence length (past_sequence_length + sequence_length) among keys - int max_sequence_length; // max sequence length for sparse layout - int max_rotary_sequence_length; // max sequence length for rotary cos/sin cache - int max_cache_sequence_length; // max sequence length for kv cache buffer - bool past_present_share_buffer; // whether past_key and present_key share buffer, so is past_value and present_value -}; - constexpr bool LAYOUT_BSNH = false; constexpr bool LAYOUT_BNSH = true; @@ -215,6 +77,7 @@ enum class AttentionBackend : int { // Experimental kernels LEAN_ATTENTION = 256, + DECODER_ATTENTION = 512, // FasterTransformer's decoder masked multihead attention }; // Environment variable to enable debug information of attention kernel to be printed. Default is 0 (disabled). @@ -245,6 +108,9 @@ constexpr const char* kDisableFlashAttention = "ORT_DISABLE_FLASH_ATTENTION"; // Environment variable to enable or disable lean attention. Default is 0 (disabled). constexpr const char* kEnableLeanAttention = "ORT_ENABLE_LEAN_ATTENTION"; +// Environment variable to enable or disable FasterTransformer's decoder masked multi-head attention. Default is 0 (enabled). +constexpr const char* kDisableDecoderAttention = "ORT_DISABLE_DECODER_ATTENTION"; + // Minimum sequence length to perfer memory efficient attention when data type is float32 constexpr const char* kMinSeqLenForEfficientAttentionFp32 = "ORT_MIN_SEQ_LEN_EFFICIENT_ATTENTION_FP32"; diff --git a/onnxruntime/contrib_ops/cpu/bert/attention_cpu_base.h b/onnxruntime/contrib_ops/cpu/bert/attention_cpu_base.h index 87938f3728750..4abe986ffa685 100644 --- a/onnxruntime/contrib_ops/cpu/bert/attention_cpu_base.h +++ b/onnxruntime/contrib_ops/cpu/bert/attention_cpu_base.h @@ -29,6 +29,7 @@ class AttentionCPUBase : public AttentionBase { Tensor* output, // output tensor Tensor* present_key, // present K output tensor (if separating present KV) Tensor* present_value, // present V output tensor (if separating present KV) + Tensor* output_qk, // Q*K output tensor (if returning Q*K value) int batch_size, // batch size (B) int sequence_length, // sequence length of Q (S) int kv_sequence_length, // sequence length of K or V (L) @@ -37,7 +38,6 @@ class AttentionCPUBase : public AttentionBase { int v_hidden_size, // hidden size of V (D_v) const Tensor* attn_bias, // additive bias applied on scaled QK. OpKernelContext* context, - Tensor* output_qk = nullptr, // output buffer for QK (if needed) int past_sequence_length = 0, // sequence length of past state bool past_present_share_buffer = false) const { AllocatorPtr allocator; @@ -109,7 +109,7 @@ class AttentionCPUBase : public AttentionBase { static_cast(mask_data), batch_size, sequence_length, kv_sequence_length, past_sequence_length, qk_head_size == 0 ? v_head_size : qk_head_size, past_data, past_key_data, present_data, - present_key_data, tp, scale, attn_bias_data, attn_bias_dims, output_qk_data, + present_key_data, output_qk_data, tp, scale, attn_bias_data, attn_bias_dims, past_present_share_buffer, max_sequence_length); // Compute the attentionScore * Value: out_tmp(B, N, S, H_v) = attention_probs(B, N, S, T) x V(B, N, T, H_v) @@ -125,6 +125,65 @@ class AttentionCPUBase : public AttentionBase { return Status::OK(); } + // For DecoderMaskedMultiHeadAttention + template + Status ApplyAttentionWithBeams(const T* Q, + const T* K, + const T* V, + const Tensor* mask_index, + const Tensor* past_key, + const Tensor* past_value, + Tensor* output, + Tensor* present_key, + Tensor* present_value, + int batch_size, + int past_sequence_length, + int max_sequence_length, + int head_size, + int v_head_size, + const Tensor* attn_bias, + bool broadcast_attn_bias_dim_0, + bool broadcast_attn_bias_dim_1, + const Tensor* cache_indir, + OpKernelContext* context, + int beam_width, + Tensor* output_qk) const { + AllocatorPtr allocator; + ORT_RETURN_IF_ERROR(context->GetTempSpaceAllocator(&allocator)); + + auto* tp = context->GetOperatorThreadPool(); + + int total_sequence_length = past_sequence_length + 1; // This is +1 because this is used during token generation via DecoderMaskedMultiHeadAttention + size_t bytes = SafeInt(batch_size) * num_heads_ * total_sequence_length * sizeof(T); + auto attention_probs = allocator->Alloc(bytes); + BufferUniquePtr scratch_buffer(attention_probs, BufferDeleter(allocator)); + + const T* past_key_data = past_key != nullptr ? past_key->Data() : nullptr; + T* present_key_data = present_key != nullptr ? present_key->MutableData() : nullptr; + const T* past_value_data = past_value != nullptr ? past_value->Data() : nullptr; + T* present_value_data = present_value != nullptr ? present_value->MutableData() : nullptr; + T* output_qk_data = (output_qk != nullptr) ? output_qk->MutableData() : nullptr; + + const int32_t* mask_index_data = mask_index != nullptr ? mask_index->Data() : nullptr; + const T* attn_bias_data = attn_bias != nullptr ? attn_bias->Data() : nullptr; + + ComputeAttentionProbsWithBeams(static_cast(attention_probs), Q, K, mask_index_data, batch_size, + past_sequence_length, max_sequence_length, head_size, past_key_data, + present_key_data, tp, attn_bias_data, broadcast_attn_bias_dim_0, + broadcast_attn_bias_dim_1, cache_indir->Data(), beam_width, output_qk_data); + + // Compute the attentionScore * Value: out_tmp(B, N, 1, H_v) = attention_probs(B, N, 1, T) x V(B, N, T, H_v) + auto out_tmp_data = allocator->Alloc(SafeInt(batch_size) * num_heads_ * v_head_size * sizeof(T)); + BufferUniquePtr out_tmp_buffer(out_tmp_data, BufferDeleter(std::move(allocator))); + + ComputeVxAttentionScoreWithBeams(output->MutableData(), static_cast(out_tmp_data), + static_cast(attention_probs), V, batch_size, + past_sequence_length, max_sequence_length, v_head_size, past_value_data, + present_value_data, cache_indir->Data(), beam_width, tp); + + return Status::OK(); + } + private: // Helper function to compute the attention probs. It does 2 things: // attention_probs(B, N, S, T) = 1/sqrt(H) x Q(B, N, S, H) x K'(B, N, T, H -> B, N, H, T) + @@ -144,11 +203,11 @@ class AttentionCPUBase : public AttentionBase { const T* past_key, // past key only (if not using past state) T* present, // present state T* present_key, // present key only (if not using present state) + T* output_qk, // Q*K output ThreadPool* tp, // thread pool float scale, // scale factor const T* attn_bias_data, // attention bias gsl::span attn_bias_dims, // attention bias shape - T* output_qk_data = nullptr, // scaled output QK buffer bool past_present_share_buffer = false, int max_sequence_length = 0) const { const int total_sequence_length = past_sequence_length + kv_sequence_length; // T = P + L @@ -208,7 +267,7 @@ class AttentionCPUBase : public AttentionBase { // Here we handle the broadcast of batch_size and num_heads dimensions. ptrdiff_t attn_bias_offset = 0; if (attn_bias_dims[0] != 1) { - attn_bias_offset += SafeInt(batch_index) * num_heads_ * probs_matrix_size; + attn_bias_offset += SafeInt(batch_index) * attn_bias_dims[1] * probs_matrix_size; } if (attn_bias_dims[1] != 1) { attn_bias_offset += head_index * probs_matrix_size; @@ -253,9 +312,9 @@ class AttentionCPUBase : public AttentionBase { }); } - if (output_qk_data != nullptr) { + if (output_qk != nullptr) { // Output the scaled Q*K^T if needed. - memcpy(output_qk_data, attention_probs, + memcpy(output_qk, attention_probs, SafeInt(batch_size) * num_heads_ * sequence_length * total_sequence_length * sizeof(T)); } @@ -360,6 +419,200 @@ class AttentionCPUBase : public AttentionBase { } }); } + + // Used for DecoderMaskedMultiHeadAttention where sequence_length = 1 + template + void ComputeAttentionProbsWithBeams(T* attention_probs, + const T* Q, + const T* K, + const int32_t* mask_index_data, + int batch_size, + int past_sequence_length, + int max_sequence_length, + int head_size, + const T* past_key_data, + T* present_key_data, + ThreadPool* tp, + const T* attn_bias_data, + bool broadcast_attn_bias_dim_0, + bool broadcast_attn_bias_dim_1, + const int32_t* cache_indir_data, + int beam_width, + T* output_qk_data) const { + float scale = scale_ == 0.0f ? 1.0f / sqrt(static_cast(head_size)) : scale_; + + TensorOpCost unit_cost; + auto total_sequence_length = past_sequence_length + 1; + const ptrdiff_t probs_matrix_size = total_sequence_length; + const ptrdiff_t probs_matrix_bytes = probs_matrix_size * sizeof(T); + + unit_cost.compute_cycles = static_cast((SafeInt(2) * head_size - 1) * total_sequence_length); + unit_cost.bytes_loaded = static_cast(SafeInt(2) * head_size * total_sequence_length * sizeof(T)); + unit_cost.bytes_stored = static_cast(SafeInt(head_size) * total_sequence_length * sizeof(T)); + + if (attn_bias_data != nullptr) { + unit_cost.bytes_loaded += static_cast(probs_matrix_bytes) * 2; + unit_cost.bytes_stored += probs_matrix_bytes; + } + + if (mask_index_data != nullptr) { + unit_cost.bytes_stored += probs_matrix_bytes; + } + + // Cost of appending current key to present key + unit_cost.compute_cycles += static_cast(head_size); + unit_cost.bytes_loaded += static_cast(head_size); + + // Parallel for loop + const int loop_len = batch_size * num_heads_; + ThreadPool::TryParallelFor(tp, loop_len, unit_cost, [&](std::ptrdiff_t begin, std::ptrdiff_t end) { + for (std::ptrdiff_t i = begin; i != end; ++i) { + const std::ptrdiff_t batch_index = i / num_heads_; + const std::ptrdiff_t head_index = i % num_heads_; + const std::ptrdiff_t beam_batch_index = batch_index / beam_width; + const T* q_vec = Q + i * head_size; + const std::ptrdiff_t attn_bias_base_offset = ((broadcast_attn_bias_dim_0 ? 0 : (beam_batch_index * num_heads_)) + + (broadcast_attn_bias_dim_1 ? 0 : head_index)) * + probs_matrix_size; + + { + // Calculate the latest position of the attention_probs + // (1, H) x (T, H)^T -> (1, T) + // Decompose into T (1, H) x (1, H)^T -> (1, 1) operations + auto last_offset = past_sequence_length + i * probs_matrix_size; + T* attention_probs_ptr = reinterpret_cast(attention_probs) + last_offset; + math::Dot(head_size, q_vec, K + i * head_size, attention_probs_ptr, nullptr); + + *attention_probs_ptr *= scale; + // Apply the attention bias and mask + if (attn_bias_data != nullptr) { + *attention_probs_ptr += attn_bias_data[attn_bias_base_offset + past_sequence_length]; + } + bool is_masked = (mask_index_data != nullptr) && + (mask_index_data[(batch_index + 1) * total_sequence_length - 1] == 0); + if (is_masked) { + *attention_probs_ptr += mask_filter_value_; + } + } + + { + // Calculate the rest of the attention_probs + for (std::ptrdiff_t j = 0; j < past_sequence_length; ++j) { + const int* beam_indices = &cache_indir_data[batch_index * max_sequence_length]; + const std::ptrdiff_t beam_offset = static_cast(beam_indices[j]) * num_heads_ * + max_sequence_length * head_size; + const std::ptrdiff_t beam_batch_offset = (beam_batch_index * beam_width * num_heads_ + head_index) * + max_sequence_length * head_size; + const T* past_k_vec = past_key_data + beam_batch_offset + beam_offset + j * head_size; + T* output = reinterpret_cast(attention_probs) + j + i * probs_matrix_size; + math::Dot(head_size, q_vec, past_k_vec, output, nullptr); + + *output *= scale; + // Apply the attention bias and mask + if (attn_bias_data != nullptr) { + *output += attn_bias_data[attn_bias_base_offset + j]; + } + bool is_masked = (mask_index_data != nullptr) && + (mask_index_data[batch_index * total_sequence_length + j] == 0); + if (is_masked) { + *output += mask_filter_value_; + } + } + } + + // Append current key to present key (past_present_share_buffer_ is true) + memcpy(present_key_data + (i * max_sequence_length + past_sequence_length) * head_size, + K + i * head_size, head_size * sizeof(T)); + } + }); + + if (output_qk_data != nullptr) { + // Output the scaled Q*K^T if needed. + memcpy(output_qk_data, attention_probs, + SafeInt(batch_size) * num_heads_ * total_sequence_length * sizeof(T)); + } + + // attention_probs(B, N, 1, T) = Softmax(attention_probs) + { + const int N = batch_size * num_heads_; + const int D = total_sequence_length; + ComputeAttentionSoftmaxInplace(attention_probs, N, D, tp); + } + } + + // Used for DecoderMaskedMultiHeadAttention where sequence_length = 1 + template + void ComputeVxAttentionScoreWithBeams(T* output, + T* tmp_buffer, + const T* attention_probs, + const T* V, + int batch_size, + int past_sequence_length, + int max_sequence_length, + int v_head_size, + const T* past_value_data, + T* present_value_data, + const int32_t* cache_indir_data, + int beam_width, + ThreadPool* tp) const { + const int total_sequence_length = past_sequence_length + 1; + + TensorOpCost unit_cost; + unit_cost.compute_cycles = static_cast(SafeInt(2) * v_head_size * total_sequence_length); + unit_cost.bytes_loaded = static_cast(SafeInt(3) * v_head_size * total_sequence_length * sizeof(T)); + unit_cost.bytes_stored = static_cast(SafeInt(2) * v_head_size * total_sequence_length * sizeof(T)); + + // Cost of appending current value to present value + unit_cost.compute_cycles += static_cast(v_head_size); + unit_cost.bytes_loaded += static_cast(v_head_size); + + ThreadPool::TryParallelFor(tp, SafeInt(batch_size) * num_heads_, unit_cost, [&](std::ptrdiff_t begin, std::ptrdiff_t end) { + for (std::ptrdiff_t i = begin; i != end; ++i) { + const std::ptrdiff_t batch_index = i / num_heads_; + const std::ptrdiff_t head_index = i % num_heads_; + const std::ptrdiff_t beam_batch_index = batch_index / beam_width; + + // Compute the attention score + // (1, T) x (T, H_v) -> (1, H_v) + // Decompose into T (1, 1) x (1, H_v) -> (1, H_v) operations and accumulate. + { + const T* attn_probs_ptr = attention_probs + (i + 1) * total_sequence_length - 1; + math::Scale(v_head_size, + static_cast(*attn_probs_ptr), + V + i * v_head_size, + output + i * v_head_size, + nullptr); + } + { + for (std::ptrdiff_t j = 0; j < past_sequence_length; ++j) { + const int* beam_indices = &cache_indir_data[batch_index * max_sequence_length]; + const std::ptrdiff_t beam_offset = static_cast(beam_indices[j]) * num_heads_ * + max_sequence_length * v_head_size; + const std::ptrdiff_t beam_batch_offset = (beam_batch_index * beam_width * num_heads_ + head_index) * + max_sequence_length * v_head_size; + const T* past_value_vec = past_value_data + beam_offset + beam_batch_offset; + const T* attn_probs_ptr = attention_probs + j + i * total_sequence_length; + + math::Scale(v_head_size, + static_cast(*attn_probs_ptr), + past_value_vec + j * v_head_size, + tmp_buffer + i * v_head_size, + nullptr); + math::Add(v_head_size, + output + i * v_head_size, + tmp_buffer + i * v_head_size, + output + i * v_head_size, + nullptr); + } + } + + // Append current value to present value (past_present_share_buffer_ is true) + memcpy(present_value_data + (i * max_sequence_length + past_sequence_length) * v_head_size, + V + i * v_head_size, + v_head_size * sizeof(T)); + } + }); + } }; } // namespace contrib diff --git a/onnxruntime/contrib_ops/cpu/bert/attention_helper.h b/onnxruntime/contrib_ops/cpu/bert/attention_helper.h index 188fc6e43b5b5..ac32a4445f3ca 100644 --- a/onnxruntime/contrib_ops/cpu/bert/attention_helper.h +++ b/onnxruntime/contrib_ops/cpu/bert/attention_helper.h @@ -31,6 +31,11 @@ void ComputeAttentionSoftcapInplace(T* scores, int sequence_length, T softcap) { MlasComputeSoftcap(scores, scores, sequence_length, softcap); } +template +void ApplyAttentionBias(T* softmax_logits, const T* attention_mask, int N) { + MlasEltwiseAdd(softmax_logits, attention_mask, softmax_logits, N); +} + template void PrepareMask(const int32_t* mask_index, gsl::span mask_index_dims, diff --git a/onnxruntime/contrib_ops/cpu/bert/attention_parameters.h b/onnxruntime/contrib_ops/cpu/bert/attention_parameters.h new file mode 100644 index 0000000000000..c3d5128948c6f --- /dev/null +++ b/onnxruntime/contrib_ops/cpu/bert/attention_parameters.h @@ -0,0 +1,122 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "contrib_ops/cpu/bert/attention_common.h" + +namespace onnxruntime { +namespace contrib { + +// Parameters deduced from node attributes and inputs/outputs. +struct AttentionParameters { + int batch_size; + int sequence_length; + int kv_sequence_length; // input sequence length of K or V + int past_sequence_length; // sequence length in past state of K or V + int total_sequence_length; // total sequence length of K or V + int max_sequence_length; // max sequence length from 4D mask + int input_hidden_size; // first dimension of weights for input projection + int hidden_size; // hidden size of Q or K + int head_size; // hidden size per head of Q or K + int v_hidden_size; // hidden size of V + int v_head_size; // hidden size per head of V + int num_heads; + int num_splits; + int rotary_embedding; + int beam_width; + bool is_unidirectional; + bool past_present_share_buffer; + bool do_rotary; + bool broadcast_attn_bias_dim_0; + bool broadcast_attn_bias_dim_1; + float mask_filter_value; + float scale; + bool use_tf32; + AttentionMaskType mask_type; + AttentionQkvFormat qkv_format; +}; + +// Parameters deduced from node attributes and inputs/outputs. +struct PackedAttentionParameters : AttentionParameters { + int token_count; +}; + +struct DecoderMaskedMultiHeadAttentionParameters : AttentionParameters { + int beam_width = 1; + + // Only NeoX style rotary embedding is supported + int rotary_embedding_dim = 0; + int t_step = 0; + + // Weather to use multihead attention(excludes matmul and bias) + bool is_mha = false; + bool is_cross_attention = false; + bool is_packed_qkv = false; + + // Useful to better use global memory bandwidth on certain CUDA architectures. + // Turned off by default for now until we fully understand performance implications + // for all types of workloads. + // Can be turned on by appropriate environment variable (see attention_common.h). + bool kv_data_in_flight = false; + + void* q = nullptr; + void* q_bias = nullptr; + + void* k = nullptr; + void* k_bias = nullptr; + + void* v = nullptr; + void* v_bias = nullptr; + + void* attention_bias = nullptr; + + void* k_cache = nullptr; + void* v_cache = nullptr; + + void* out = nullptr; + void* out_qk = nullptr; + + const int32_t* cache_indir = nullptr; + const int32_t* mask = nullptr; // [B, total_sequence_length] +}; + +// Parameters deduced from node attributes and inputs/outputs. +struct GroupQueryAttentionParameters : AttentionParameters { + int seqlen_past_kv_cache; // sequence length of past kv tensor + int seqlen_present_kv_cache; // sequence length of present kv tensor + int kv_hidden_size; + int kv_num_heads; + int num_splits; // number of splits for splitkv + int rotary_dim; // rotary embedding dimension + int local_window_size; // The window size excludes current token. It only includes tokens on the left side. + bool kv_share_buffer; + bool is_packed_qkv; + bool is_subsequent_prompt; // indicates whether we have past context and seqlen > 1 + bool is_first_prompt; // indicates whether this is first decoding step + bool rotary_interleaved; + bool use_smooth_softmax; + float softcap; + AttentionQkvFormat past_kv_format; + int zeros_count; + int* zero_ptr; +}; + +// Parameters for sparse attention. +struct SparseAttentionParameters : AttentionParameters { + int kv_hidden_size; // hidden size of key or value + int kv_num_heads; // number of heads of key or value + bool do_rotary; // whether to use rotary embedding + bool rotary_interleaved; // whether to use interleaved rotary embedding + int rotary_dim; // rotary embedding dimension + int sparse_block_size; // block size for sparse attention + int num_sparse_layout; // number of sparse layout + int stride_col_indices; // shape of block_col_indices is [num_sparse_layout, stride_col_indices] + int stride_row_indices; // shape of block_row_indices is [num_sparse_layout, stride_row_indices] + bool is_packed_qkv; // whether qkv is packed + int max_rotary_sequence_length; // max sequence length for rotary cos/sin cache + int max_cache_sequence_length; // max sequence length for kv cache buffer +}; + +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cpu/bert/decoder_masked_multihead_attention.cc b/onnxruntime/contrib_ops/cpu/bert/decoder_masked_multihead_attention.cc index e6f65f92e14f4..0d2de59c05394 100644 --- a/onnxruntime/contrib_ops/cpu/bert/decoder_masked_multihead_attention.cc +++ b/onnxruntime/contrib_ops/cpu/bert/decoder_masked_multihead_attention.cc @@ -1,11 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "attention_cpu_base.h" -#include "attention_utils.h" -#include "core/platform/env_var_utils.h" +#include "contrib_ops/cpu/bert/attention_cpu_base.h" +#include "contrib_ops/cpu/bert/attention_parameters.h" +#include "contrib_ops/cpu/bert/attention_utils.h" #include "contrib_ops/cpu/bert/multihead_attention_helper.h" #include "contrib_ops/cpu/bert/decoder_masked_multihead_attention.h" +#include "core/platform/env_var_utils.h" using namespace ::onnxruntime::common; using namespace ONNX_NAMESPACE; @@ -65,7 +66,7 @@ Status DecoderMaskedMultiHeadAttention::Compute(OpKernelContext* context) con const Tensor* cache_indir = context->Input(kCacheIndirectionInputIndex); const Tensor* bias = context->Input(kBiasIndex); - DecoderMaskedMultiHeadAttentionParams parameters; + DecoderMaskedMultiHeadAttentionParameters parameters; bool is_unidirectional = false; ORT_RETURN_IF_ERROR(multihead_attention_helper::CheckInputs(query, @@ -76,6 +77,7 @@ Status DecoderMaskedMultiHeadAttention::Compute(OpKernelContext* context) con attention_bias, past_key, past_value, + cache_indir, past_seq_len, ¶meters, num_heads_, @@ -188,9 +190,9 @@ Status DecoderMaskedMultiHeadAttention::Compute(OpKernelContext* context) con return ApplyAttention(Q.GetMutable()->MutableData(), key->Data(), value->Data(), - mask_index, nullptr /* past */, past_key, past_value, output, present_key, present_value, + mask_index, nullptr /* past */, past_key, past_value, output, present_key, present_value, output_qk, batch_size, 1 /* sequence_length */, parameters.kv_sequence_length, - head_size, v_head_size, v_hidden_size, attention_bias, context, output_qk); + head_size, v_head_size, v_hidden_size, attention_bias, context); } OrtValue K, V; @@ -204,9 +206,9 @@ Status DecoderMaskedMultiHeadAttention::Compute(OpKernelContext* context) con return ApplyAttention(Q.GetMutable()->MutableData(), K.GetMutable()->MutableData(), V.GetMutable()->MutableData(), - mask_index, nullptr /* past */, past_key, past_value, output, present_key, present_value, + mask_index, nullptr /* past */, past_key, past_value, output, present_key, present_value, output_qk, batch_size, 1 /* sequence_length */, parameters.kv_sequence_length, - head_size, v_head_size, v_hidden_size, attention_bias, context, output_qk, + head_size, v_head_size, v_hidden_size, attention_bias, context, parameters.past_sequence_length, true /* past_present_share_buffer */); } @@ -221,253 +223,5 @@ Status DecoderMaskedMultiHeadAttention::Compute(OpKernelContext* context) con beam_width_value, output_qk); } -template -Status DecoderMaskedMultiHeadAttention::ApplyAttentionWithBeams( - const T* Q, - const T* K, - const T* V, - const Tensor* mask_index, - const Tensor* past_key, - const Tensor* past_value, - Tensor* output, - Tensor* present_key, - Tensor* present_value, - int batch_size, - int past_sequence_length, - int max_sequence_length, - int head_size, - int v_head_size, - const Tensor* attn_bias, - bool broadcast_attn_bias_dim_0, - bool broadcast_attn_bias_dim_1, - const Tensor* cache_indir, - OpKernelContext* context, - int beam_width, - Tensor* output_qk) const { - AllocatorPtr allocator; - ORT_RETURN_IF_ERROR(context->GetTempSpaceAllocator(&allocator)); - - auto* tp = context->GetOperatorThreadPool(); - - int total_sequence_length = past_sequence_length + 1; - size_t bytes = SafeInt(batch_size) * num_heads_ * total_sequence_length * sizeof(T); - auto attention_probs = allocator->Alloc(bytes); - BufferUniquePtr scratch_buffer(attention_probs, BufferDeleter(allocator)); - - T* output_qk_data = (output_qk != nullptr) ? output_qk->MutableData() : nullptr; - - const int32_t* mask_index_data = mask_index != nullptr ? mask_index->Data() : nullptr; - const T* attn_bias_data = attn_bias != nullptr ? attn_bias->Data() : nullptr; - - ComputeAttentionProbsWithBeams(static_cast(attention_probs), Q, K, mask_index_data, batch_size, - past_sequence_length, max_sequence_length, head_size, past_key->Data(), - present_key->MutableData(), tp, attn_bias_data, broadcast_attn_bias_dim_0, - broadcast_attn_bias_dim_1, cache_indir->Data(), beam_width, output_qk_data); - - // Compute the attentionScore * Value: out_tmp(B, N, 1, H_v) = attention_probs(B, N, 1, T) x V(B, N, T, H_v) - auto out_tmp_data = allocator->Alloc(SafeInt(batch_size) * num_heads_ * v_head_size * sizeof(T)); - BufferUniquePtr out_tmp_buffer(out_tmp_data, BufferDeleter(std::move(allocator))); - - ComputeVxAttentionScoreWithBeams(output->MutableData(), static_cast(out_tmp_data), - static_cast(attention_probs), V, batch_size, - past_sequence_length, max_sequence_length, v_head_size, past_value->Data(), - present_value->MutableData(), cache_indir->Data(), beam_width, tp); - - return Status::OK(); -} - -template -void DecoderMaskedMultiHeadAttention::ComputeAttentionProbsWithBeams( - T* attention_probs, - const T* Q, - const T* K, - const int32_t* mask_index_data, - int batch_size, - int past_sequence_length, - int max_sequence_length, - int head_size, - const T* past_key_data, - T* present_key_data, - ThreadPool* tp, - const T* attn_bias_data, - bool broadcast_attn_bias_dim_0, - bool broadcast_attn_bias_dim_1, - const int32_t* cache_indir_data, - int beam_width, - T* output_qk_data) const { - float scale = scale_ == 0.0f ? 1.0f / sqrt(static_cast(head_size)) : scale_; - - TensorOpCost unit_cost; - auto total_sequence_length = past_sequence_length + 1; - const ptrdiff_t probs_matrix_size = total_sequence_length; - const ptrdiff_t probs_matrix_bytes = probs_matrix_size * sizeof(T); - - unit_cost.compute_cycles = static_cast((SafeInt(2) * head_size - 1) * total_sequence_length); - unit_cost.bytes_loaded = static_cast(SafeInt(2) * head_size * total_sequence_length * sizeof(T)); - unit_cost.bytes_stored = static_cast(SafeInt(head_size) * total_sequence_length * sizeof(T)); - - if (attn_bias_data != nullptr) { - unit_cost.bytes_loaded += static_cast(probs_matrix_bytes) * 2; - unit_cost.bytes_stored += probs_matrix_bytes; - } - - if (mask_index_data != nullptr) { - unit_cost.bytes_stored += probs_matrix_bytes; - } - - // Cost of appending current key to present key - unit_cost.compute_cycles += static_cast(head_size); - unit_cost.bytes_loaded += static_cast(head_size); - - // Parallel for loop - const int loop_len = batch_size * num_heads_; - ThreadPool::TryParallelFor(tp, loop_len, unit_cost, [&](std::ptrdiff_t begin, std::ptrdiff_t end) { - for (std::ptrdiff_t i = begin; i != end; ++i) { - const std::ptrdiff_t batch_index = i / num_heads_; - const std::ptrdiff_t head_index = i % num_heads_; - const std::ptrdiff_t beam_batch_index = batch_index / beam_width; - const T* q_vec = Q + i * head_size; - const std::ptrdiff_t attn_bias_base_offset = ((broadcast_attn_bias_dim_0 ? 0 : (beam_batch_index * num_heads_)) + - (broadcast_attn_bias_dim_1 ? 0 : head_index)) * - probs_matrix_size; - - { - // Calculate the latest position of the attention_probs - // (1, H) x (T, H)^T -> (1, T) - // Decompose into T (1, H) x (1, H)^T -> (1, 1) operations - auto last_offset = past_sequence_length + i * probs_matrix_size; - T* attention_probs_ptr = reinterpret_cast(attention_probs) + last_offset; - math::Dot(head_size, q_vec, K + i * head_size, attention_probs_ptr, nullptr); - - *attention_probs_ptr *= scale; - // Apply the attention bias and mask - if (attn_bias_data != nullptr) { - *attention_probs_ptr += attn_bias_data[attn_bias_base_offset + past_sequence_length]; - } - bool is_masked = (mask_index_data != nullptr) && - (mask_index_data[(batch_index + 1) * total_sequence_length - 1] == 0); - if (is_masked) { - *attention_probs_ptr += mask_filter_value_; - } - } - - { - // Calculate the rest of the attention_probs - for (std::ptrdiff_t j = 0; j < past_sequence_length; ++j) { - const int* beam_indices = &cache_indir_data[batch_index * max_sequence_length]; - const std::ptrdiff_t beam_offset = static_cast(beam_indices[j]) * num_heads_ * - max_sequence_length * head_size; - const std::ptrdiff_t beam_batch_offset = (beam_batch_index * beam_width * num_heads_ + head_index) * - max_sequence_length * head_size; - const T* past_k_vec = past_key_data + beam_batch_offset + beam_offset + j * head_size; - T* output = reinterpret_cast(attention_probs) + j + i * probs_matrix_size; - math::Dot(head_size, q_vec, past_k_vec, output, nullptr); - - *output *= scale; - // Apply the attention bias and mask - if (attn_bias_data != nullptr) { - *output += attn_bias_data[attn_bias_base_offset + j]; - } - bool is_masked = (mask_index_data != nullptr) && - (mask_index_data[batch_index * total_sequence_length + j] == 0); - if (is_masked) { - *output += mask_filter_value_; - } - } - } - // Append current key to present key (past_present_share_buffer_ is true) - memcpy(present_key_data + (i * max_sequence_length + past_sequence_length) * head_size, - K + i * head_size, head_size * sizeof(T)); - } - }); - - if (output_qk_data != nullptr) { - // Output the scaled Q*K^T if needed. - memcpy(output_qk_data, attention_probs, - SafeInt(batch_size) * num_heads_ * total_sequence_length * sizeof(T)); - } - - // attention_probs(B, N, 1, T) = Softmax(attention_probs) - { - const int N = batch_size * num_heads_; - const int D = total_sequence_length; - ComputeAttentionSoftmaxInplace(attention_probs, N, D, tp); - } -} - -template -void DecoderMaskedMultiHeadAttention::ComputeVxAttentionScoreWithBeams( - T* output, - T* tmp_buffer, - const T* attention_probs, - const T* V, - int batch_size, - int past_sequence_length, - int max_sequence_length, - int v_head_size, - const T* past_value_data, - T* present_value_data, - const int32_t* cache_indir_data, - int beam_width, - ThreadPool* tp) const { - const int total_sequence_length = past_sequence_length + 1; - - TensorOpCost unit_cost; - unit_cost.compute_cycles = static_cast(SafeInt(2) * v_head_size * total_sequence_length); - unit_cost.bytes_loaded = static_cast(SafeInt(3) * v_head_size * total_sequence_length * sizeof(T)); - unit_cost.bytes_stored = static_cast(SafeInt(2) * v_head_size * total_sequence_length * sizeof(T)); - - // Cost of appending current value to present value - unit_cost.compute_cycles += static_cast(v_head_size); - unit_cost.bytes_loaded += static_cast(v_head_size); - - ThreadPool::TryParallelFor( - tp, SafeInt(batch_size) * num_heads_, unit_cost, [&](std::ptrdiff_t begin, std::ptrdiff_t end) { - for (std::ptrdiff_t i = begin; i != end; ++i) { - const std::ptrdiff_t batch_index = i / num_heads_; - const std::ptrdiff_t head_index = i % num_heads_; - const std::ptrdiff_t beam_batch_index = batch_index / beam_width; - - // Compute the attention score - // (1, T) x (T, H_v) -> (1, H_v) - // Decompose into T (1, 1) x (1, H_v) -> (1, H_v) operations and accumulate. - { - const T* attn_probs_ptr = attention_probs + (i + 1) * total_sequence_length - 1; - math::Scale(v_head_size, - static_cast(*attn_probs_ptr), - V + i * v_head_size, - output + i * v_head_size, - nullptr); - } - { - for (std::ptrdiff_t j = 0; j < past_sequence_length; ++j) { - const int* beam_indices = &cache_indir_data[batch_index * max_sequence_length]; - const std::ptrdiff_t beam_offset = static_cast(beam_indices[j]) * num_heads_ * - max_sequence_length * v_head_size; - const std::ptrdiff_t beam_batch_offset = (beam_batch_index * beam_width * num_heads_ + head_index) * - max_sequence_length * v_head_size; - const T* past_value_vec = past_value_data + beam_offset + beam_batch_offset; - const T* attn_probs_ptr = attention_probs + j + i * total_sequence_length; - - math::Scale(v_head_size, - static_cast(*attn_probs_ptr), - past_value_vec + j * v_head_size, - tmp_buffer + i * v_head_size, - nullptr); - math::Add(v_head_size, - output + i * v_head_size, - tmp_buffer + i * v_head_size, - output + i * v_head_size, - nullptr); - } - } - // Append current value to present value (past_present_share_buffer_ is true) - memcpy(present_value_data + (i * max_sequence_length + past_sequence_length) * v_head_size, - V + i * v_head_size, - v_head_size * sizeof(T)); - } - }); -} - } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cpu/bert/decoder_masked_multihead_attention.h b/onnxruntime/contrib_ops/cpu/bert/decoder_masked_multihead_attention.h index d5167e8989669..1a4bc72e2f73a 100644 --- a/onnxruntime/contrib_ops/cpu/bert/decoder_masked_multihead_attention.h +++ b/onnxruntime/contrib_ops/cpu/bert/decoder_masked_multihead_attention.h @@ -13,57 +13,6 @@ template class DecoderMaskedMultiHeadAttention final : public OpKernel, public AttentionCPUBase { public: DecoderMaskedMultiHeadAttention(const OpKernelInfo& info); - Status ApplyAttentionWithBeams(const T* Q, - const T* K, - const T* V, - const Tensor* mask_index, - const Tensor* past_key, - const Tensor* past_value, - Tensor* output, - Tensor* present_key, - Tensor* present_value, - int batch_size, - int past_sequence_length, - int max_sequence_length, - int head_size, - int v_head_size, - const Tensor* attn_bias, - bool broadcast_attn_bias_dim_0, - bool broadcast_attn_bias_dim_1, - const Tensor* cache_indir, - OpKernelContext* context, - int beam_width, - Tensor* output_qk = nullptr) const; - void ComputeAttentionProbsWithBeams(T* attention_probs, - const T* Q, - const T* K, - const int32_t* mask_index_data, - int batch_size, - int past_sequence_length, - int max_sequence_length, - int head_size, - const T* past_key, - T* present_key, - ThreadPool* tp, - const T* attn_bias_data, - bool broadcast_attn_bias_dim_0, - bool broadcast_attn_bias_dim_1, - const int32_t* cache_indir_data, - int beam_width, - T* output_qk_data = nullptr) const; - void ComputeVxAttentionScoreWithBeams(T* output, - T* tmp_buffer, - const T* attention_probs, - const T* V, - int batch_size, - int past_sequence_length, - int max_sequence_length, - int v_head_size, - const T* past_value, - T* present_value, - const int32_t* cache_indir_data, - int beam_width, - ThreadPool* tp) const; Status Compute(OpKernelContext* context) const override; protected: diff --git a/onnxruntime/contrib_ops/cpu/bert/gqa_attention_base.h b/onnxruntime/contrib_ops/cpu/bert/gqa_attention_base.h index 70d66e534ee8a..c79508cbae273 100644 --- a/onnxruntime/contrib_ops/cpu/bert/gqa_attention_base.h +++ b/onnxruntime/contrib_ops/cpu/bert/gqa_attention_base.h @@ -4,10 +4,11 @@ #pragma once #include "contrib_ops/cpu/bert/attention_base.h" +#include "contrib_ops/cpu/bert/attention_common.h" #include "contrib_ops/cpu/bert/attention_helper.h" +#include "contrib_ops/cpu/bert/attention_parameters.h" #include "core/common/common.h" -#include "contrib_ops/cpu/bert/attention_common.h" #include "core/common/safeint.h" #include "core/framework/op_kernel.h" @@ -50,6 +51,7 @@ class GQAAttentionBase { Status ApplyAttention(const T* Q, // Q data with shape BxNxSxH const T* K, // K data with shape BxN_kvxSxH const T* V, // V data with shape BxN_kvxSxH + const Tensor* attention_bias, // Attention bias to add to QxK' const Tensor* past_key, // past K input tensor (if not using past state) const Tensor* past_value, // past V input tensor (if not using past state) Tensor* output, // output tensor @@ -87,14 +89,18 @@ class GQAAttentionBase { const T* past_value_data = past_value != nullptr ? past_value->Data() : nullptr; T* present_value_data = present_value != nullptr ? present_value->MutableData() : nullptr; + const T* attention_bias_data = attention_bias != nullptr ? attention_bias->Data() : nullptr; + auto attention_bias_shape = attention_bias != nullptr ? attention_bias->Shape().GetDims() : gsl::span{}; + bool past_present_share_buffer = past_key_data == present_key_data && past_value_data == present_value_data; const T* k = packed_qkv ? Q + num_heads_ * sequence_length * head_size : K; if (gqa_mlas_supported) { - ComputeAttentionProbs(static_cast(attention_probs), Q, k, seqlens_k->Data(), batch_size, - sequence_length, seqlen_past_kv_cache, seqlen_present_kv_cache, head_size, past_key_data, - present_key_data, past_present_share_buffer, packed_qkv, is_prompt, tp, allocator); + ComputeAttentionProbs(static_cast(attention_probs), Q, k, seqlens_k->Data(), attention_bias_data, + batch_size, sequence_length, attention_bias_shape, seqlen_past_kv_cache, seqlen_present_kv_cache, + head_size, past_key_data, present_key_data, past_present_share_buffer, packed_qkv, is_prompt, + tp, allocator); // Compute the attentionScore * Value: out(B, N, S, H_v) = attention_probs(B, N, S, T) x V(B, N, T, H_v) const T* v = packed_qkv ? Q + (num_heads_ + kv_num_heads_) * sequence_length * head_size : V; @@ -104,9 +110,10 @@ class GQAAttentionBase { hidden_size, past_value_data, present_value_data, past_present_share_buffer, packed_qkv, is_prompt, tp, allocator); } else { - ComputeAttentionProbs(static_cast(attention_probs), Q, k, seqlens_k->Data(), batch_size, - sequence_length, seqlen_past_kv_cache, seqlen_present_kv_cache, head_size, past_key_data, - present_key_data, past_present_share_buffer, packed_qkv, is_prompt, tp, allocator); + ComputeAttentionProbs(static_cast(attention_probs), Q, k, seqlens_k->Data(), attention_bias_data, + batch_size, sequence_length, attention_bias_shape, seqlen_past_kv_cache, seqlen_present_kv_cache, + head_size, past_key_data, present_key_data, past_present_share_buffer, packed_qkv, is_prompt, + tp, allocator); // Compute the attentionScore * Value: out(B, N, S, H_v) = attention_probs(B, N, S, T) x V(B, N, T, H_v) const T* v = packed_qkv ? Q + (num_heads_ + kv_num_heads_) * sequence_length * head_size : V; @@ -126,22 +133,24 @@ class GQAAttentionBase { // attention_probs(B, N, S, T) = Softmax(attention_probs) // If T is float32, U is float32. If T is float16, U could be float16 or float32. template - void ComputeAttentionProbs(U* attention_probs, // output buffer with size BxNxSxT - const T* Q, // Q data. Its size is BxNxSxH - const T* K, // k data. Its size is BxNxLxH - const int32_t* seqlens_k, // total - 1 sequence lengths tensor - const size_t batch_size, // batch size of self-attention - const size_t sequence_length, // sequence length of self-attention (S) - const size_t past_buffer_sequence_length, // sequence length of past state - const size_t present_buffer_sequence_length, // sequence length of present state - const size_t head_size, // head size of self-attention - const T* past_key, // past key only - T* present_key, // present key only - const bool past_present_share_buffer, // whether present key and value share the same buffer - const bool packed_qkv, // whether Q, K, V are packed - const bool is_prompt, // whether it is prompt - ThreadPool* tp, // thread pool - AllocatorPtr allocator) const { // allocator for temporary buffer + void ComputeAttentionProbs(U* attention_probs, // output buffer with size BxNxSxT + const T* Q, // Q data. Its size is BxNxSxH + const T* K, // k data. Its size is BxNxLxH + const int32_t* seqlens_k, // total - 1 sequence lengths tensor + const T* attention_bias, // optional attention bias + const size_t batch_size, // batch size of self-attention + const size_t sequence_length, // sequence length of self-attention (S) + const gsl::span attention_bias_shape, // shape of the attention bias + const size_t past_buffer_sequence_length, // sequence length of past state + const size_t present_buffer_sequence_length, // sequence length of present state + const size_t head_size, // head size of self-attention + const T* past_key, // past key only + T* present_key, // present key only + const bool past_present_share_buffer, // whether present key and value share the same buffer + const bool packed_qkv, // whether Q, K, V are packed + const bool is_prompt, // whether it is prompt + ThreadPool* tp, // thread pool + AllocatorPtr allocator) const { // allocator for temporary buffer const ptrdiff_t packed_batch_stride = packed_qkv ? SafeInt(num_heads_ + 2 * kv_num_heads_) * sequence_length * head_size : SafeInt(0); @@ -189,6 +198,24 @@ class GQAAttentionBase { const ptrdiff_t output_offset = SafeInt(i) * sequence_length * present_buffer_sequence_length; U* output = attention_probs + output_offset; + // Compute attention bias offset based on the batch and head indexes + // Attention bias is of shape (B or 1, H or 1, S, T) so handle broadcasting + const T* attention_bias_thread = nullptr; + ptrdiff_t attention_total_seqlen = 0; + if (attention_bias != nullptr) { + ptrdiff_t attention_bias_offset = 0; + attention_total_seqlen = static_cast(attention_bias_shape[3]); + const ptrdiff_t attention_matrix_size = sequence_length * attention_total_seqlen; + if (attention_bias_shape[0] != 1) { + attention_bias_offset += SafeInt(batch_index) * attention_bias_shape[1] * attention_matrix_size; + } + if (attention_bias_shape[1] != 1) { + attention_bias_offset += SafeInt(head_index) * attention_matrix_size; + } + + attention_bias_thread = attention_bias + attention_bias_offset; + } + const T* k; if (packed_qkv) { k = K + packed_batch_stride * batch_index + kv_input_chunk_length * (head_index / kv_num_heads_factor); @@ -242,7 +269,16 @@ class GQAAttentionBase { U* output_softmax = output; for (size_t seq = 0; seq < sequence_length; seq++) { size_t seq_causal_length = past_seqlen + seq + 1; - if (local_window_size_ > 0 && seq_causal_length > static_cast(local_window_size_) + 1) { + + // local_window_size does not include the current query token, while window_size includes it. + const bool should_apply_local_window = local_window_size_ >= 0 && + seq_causal_length > static_cast(local_window_size_) + 1; + + const size_t start_offset = should_apply_local_window ? seq_causal_length - local_window_size_ - 1 : 0; + const size_t window_size = should_apply_local_window ? local_window_size_ + 1 : seq_causal_length; + + // Mask everything before local window, if local window should be applied + if (should_apply_local_window) { for (size_t total_seq_id = 0; total_seq_id < seq_causal_length - local_window_size_ - 1; total_seq_id++) { if constexpr (std::is_same::value) { output_softmax[total_seq_id] = 0.f; @@ -250,27 +286,34 @@ class GQAAttentionBase { output_softmax[total_seq_id] = MLFloat16::FromBits(static_cast(0)); } } - if (softcap_ > 0.f) { - ComputeAttentionSoftcapInplace(output_softmax + seq_causal_length - local_window_size_ - 1, - local_window_size_ + 1, static_cast(softcap_)); - } - if (use_smooth_softmax_) { - ComputeSmoothSoftmaxInplace(output_softmax + seq_causal_length - local_window_size_ - 1, 1, - local_window_size_ + 1, nullptr); + } + + if (softcap_ > 0.f) { + ComputeAttentionSoftcapInplace(output_softmax + start_offset, static_cast(window_size), + static_cast(softcap_)); + } + + // Add attention bias to QxK' if provided + // TODO (#23982): Implement bias addition during softmax computation in GQA CPU operator + if (attention_bias_thread != nullptr) { + if constexpr (std::is_same_v) { + ApplyAttentionBias(output_softmax + start_offset, attention_bias_thread + start_offset, + static_cast(window_size)); } else { - ComputeAttentionSoftmaxInplace(output_softmax + seq_causal_length - local_window_size_ - 1, 1, - local_window_size_ + 1, nullptr); + static_assert(std::is_same_v && std::is_same_v); + size_t bytes = window_size * sizeof(float); + auto attention_bias_thread_fp32 = static_cast(allocator->Alloc(bytes)); + BufferUniquePtr scratch_buffer(attention_bias_thread_fp32, BufferDeleter(allocator)); + + MlasConvertHalfToFloatBuffer(attention_bias_thread + start_offset, attention_bias_thread_fp32, window_size); + ApplyAttentionBias(output_softmax + start_offset, attention_bias_thread_fp32, static_cast(window_size)); } + } + + if (use_smooth_softmax_) { + ComputeSmoothSoftmaxInplace(output_softmax + start_offset, 1, static_cast(window_size), nullptr); } else { - if (softcap_ > 0.f) { - ComputeAttentionSoftcapInplace(output_softmax, static_cast(seq_causal_length), - static_cast(softcap_)); - } - if (use_smooth_softmax_) { - ComputeSmoothSoftmaxInplace(output_softmax, 1, static_cast(seq_causal_length), nullptr); - } else { - ComputeAttentionSoftmaxInplace(output_softmax, 1, static_cast(seq_causal_length), nullptr); - } + ComputeAttentionSoftmaxInplace(output_softmax + start_offset, 1, static_cast(window_size), nullptr); } // set causal [seq_causal_length, total_seqlen) to 0.f @@ -283,6 +326,10 @@ class GQAAttentionBase { } output_softmax += present_buffer_sequence_length; + + if (attention_bias_thread != nullptr) { + attention_bias_thread += attention_total_seqlen; + } } } }); diff --git a/onnxruntime/contrib_ops/cpu/bert/group_query_attention.cc b/onnxruntime/contrib_ops/cpu/bert/group_query_attention.cc index 8f662cd388c6d..9c7530f0126bb 100644 --- a/onnxruntime/contrib_ops/cpu/bert/group_query_attention.cc +++ b/onnxruntime/contrib_ops/cpu/bert/group_query_attention.cc @@ -52,6 +52,8 @@ Status GroupQueryAttention::Compute(OpKernelContext* context) const { const Tensor* total_seqlen_tensor = context->Input(6); const Tensor* cos_cache = context->Input(7); const Tensor* sin_cache = context->Input(8); + const Tensor* position_ids = context->Input(9); + const Tensor* attention_bias = context->Input(10); GroupQueryAttentionParameters parameters = {}; ORT_RETURN_IF_ERROR(group_query_attention_helper::CheckInputs(query, @@ -69,6 +71,10 @@ Status GroupQueryAttention::Compute(OpKernelContext* context) const { scale_, softcap_)); + ORT_RETURN_IF_ERROR(group_query_attention_helper::CheckCustomAttentionInputs(position_ids, + attention_bias, + parameters)); + const int batch_size = parameters.batch_size; const int sequence_length = parameters.sequence_length; const int present_kv_seqlen = parameters.seqlen_present_kv_cache; @@ -129,9 +135,13 @@ Status GroupQueryAttention::Compute(OpKernelContext* context) const { auto* tp = context->GetOperatorThreadPool(); // Generate position ids const int pos_ids_size = parameters.is_first_prompt ? 1 : batch_size * sequence_length; - std::vector pos_ids(pos_ids_size); - if (parameters.is_first_prompt) { - pos_ids[0] = static_cast(0); + std::vector default_pos_ids(pos_ids_size); + const int64_t* pos_ids_data = default_pos_ids.data(); + + if (position_ids != nullptr) { + pos_ids_data = position_ids->Data(); + } else if (parameters.is_first_prompt) { + default_pos_ids[0] = static_cast(0); } else { // Note: As of now, continuous decoding supports only batch size 1 and token generation supports only sequence length 1. for (int b = 0; b < batch_size; b++) { @@ -139,13 +149,14 @@ Status GroupQueryAttention::Compute(OpKernelContext* context) const { const int past_seqlen = total_seqlen - sequence_length; for (int s = 0; s < sequence_length; s++) { if (past_seqlen + s < total_seqlen) { - pos_ids[b * sequence_length + s] = static_cast(past_seqlen) + s; + default_pos_ids[b * sequence_length + s] = static_cast(past_seqlen) + s; } else { - pos_ids[b * sequence_length + s] = static_cast(1); + default_pos_ids[b * sequence_length + s] = static_cast(1); } } } } + // Initialize separate buffers for rotary embeddings const T* q_input; const T* k_input; @@ -165,7 +176,7 @@ Status GroupQueryAttention::Compute(OpKernelContext* context) const { } // Run rotary embedding for Q and K ORT_RETURN_IF_ERROR(RunRotaryEmbedding(tp, rotary_params, q_input, - pos_ids.data(), cos_cache->Data(), + pos_ids_data, cos_cache->Data(), sin_cache->Data(), q_rotary, rotary_interleaved_)); rotary_params.num_heads = kv_num_heads_; @@ -174,7 +185,7 @@ Status GroupQueryAttention::Compute(OpKernelContext* context) const { rotary_params.batch_stride = kv_num_heads_ * rotary_params.head_stride; } ORT_RETURN_IF_ERROR(RunRotaryEmbedding(tp, rotary_params, k_input, - pos_ids.data(), cos_cache->Data(), + pos_ids_data, cos_cache->Data(), sin_cache->Data(), k_rotary, rotary_interleaved_)); // Pack V into rotary QKV buffer if (packed_qkv) { @@ -192,9 +203,10 @@ Status GroupQueryAttention::Compute(OpKernelContext* context) const { } ORT_RETURN_IF_ERROR(context->GetTempSpaceAllocator(&allocator)); + // Compute the attention score and apply the score to V return ApplyAttention(q_rotary, packed_qkv ? nullptr : k_rotary, packed_qkv ? nullptr : V.Get().Data(), - past_key, past_value, output, present_k, present_v, + attention_bias, past_key, past_value, output, present_k, present_v, seqlens_k, parameters, allocator, context); } } // namespace contrib diff --git a/onnxruntime/contrib_ops/cpu/bert/group_query_attention_helper.h b/onnxruntime/contrib_ops/cpu/bert/group_query_attention_helper.h index 4cc5a4228dc8c..fa0d33e891f46 100644 --- a/onnxruntime/contrib_ops/cpu/bert/group_query_attention_helper.h +++ b/onnxruntime/contrib_ops/cpu/bert/group_query_attention_helper.h @@ -6,6 +6,7 @@ #include "core/common/common.h" #include "core/providers/common.h" #include "contrib_ops/cpu/bert/attention_common.h" +#include "contrib_ops/cpu/bert/attention_parameters.h" namespace onnxruntime { namespace contrib { @@ -288,6 +289,50 @@ Status CheckInputs(const T* query, return CheckInputs(query, key, value, past_key, past_value, cos_cache, sin_cache, parameters, num_heads, kv_num_heads, seqlens_k, total_seqlen, scale, softcap); } + +template +Status CheckCustomAttentionInputs(const T* position_ids, + const T* attention_bias, + const GroupQueryAttentionParameters& parameters) { + if (position_ids != nullptr) { + const auto& pos_ids_shape = position_ids->Shape(); + if (pos_ids_shape[0] != parameters.batch_size) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "position_ids dimension 0 must be equal to the batch size, got ", pos_ids_shape[0]); + } + + if (pos_ids_shape[1] < parameters.sequence_length) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "position_ids dimension 1 must be atleast sequence length, got ", pos_ids_shape[1]); + } + } + + if (attention_bias != nullptr) { + const auto& attn_bias_shape = attention_bias->Shape(); + if ((attn_bias_shape[0] != parameters.batch_size) && (attn_bias_shape[0] != 1)) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "attention_bias dimension 0 must be equal to the batch size or 1, got ", attn_bias_shape[0]); + } + + if ((attn_bias_shape[1] != parameters.num_heads) && (attn_bias_shape[1] != 1)) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "attention_bias dimension 1 must be equal to the num heads or 1, got ", attn_bias_shape[1]); + } + + if (attn_bias_shape[2] != parameters.sequence_length) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "attention_bias dimension 2 must be equal to the sequence length, got ", attn_bias_shape[2]); + } + + if (attn_bias_shape[3] != parameters.total_sequence_length) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "attention_bias dimension 3 must be equal to total_sequence_length, got ", attn_bias_shape[3]); + } + } + + return Status::OK(); +} + } // namespace group_query_attention_helper } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cpu/bert/multihead_attention.cc b/onnxruntime/contrib_ops/cpu/bert/multihead_attention.cc index ca818f09c4b1e..996f913ef6565 100644 --- a/onnxruntime/contrib_ops/cpu/bert/multihead_attention.cc +++ b/onnxruntime/contrib_ops/cpu/bert/multihead_attention.cc @@ -1,10 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "attention_cpu_base.h" -#include "multihead_attention.h" -#include "multihead_attention_helper.h" -#include "attention_utils.h" +#include "contrib_ops/cpu/bert/attention_common.h" +#include "contrib_ops/cpu/bert/attention_cpu_base.h" +#include "contrib_ops/cpu/bert/multihead_attention.h" +#include "contrib_ops/cpu/bert/multihead_attention_helper.h" +#include "contrib_ops/cpu/bert/attention_utils.h" #include "core/common/common.h" #include "core/framework/tensorprotoutils.h" @@ -48,6 +49,8 @@ MultiHeadAttention::MultiHeadAttention(const OpKernelInfo& info) : OpKernel(i l2_cache_size_ = env.GetL2CacheSize(); disable_flash_ = ParseEnvironmentVariableWithDefault(attention::kDisableFlashAttention, false); + + disable_decoder_attention_ = ParseEnvironmentVariableWithDefault(attention::kDisableDecoderAttention, false); } template @@ -60,6 +63,8 @@ Status MultiHeadAttention::Compute(OpKernelContext* context) const { const Tensor* attn_bias = context->Input(5); const Tensor* past_key = context->Input(6); const Tensor* past_value = context->Input(7); + const Tensor* past_sequence_length = context->Input(8); + const Tensor* cache_indirection = context->Input(9); if (query->Shape().GetDims().size() == 5) { ORT_NOT_IMPLEMENTED("Packed QKV of shape (B, L, N, 3, H) not implemented for CPU"); @@ -68,8 +73,12 @@ Status MultiHeadAttention::Compute(OpKernelContext* context) const { ORT_NOT_IMPLEMENTED("Packed KV not implemented for CPU"); } + bool past_present_share_buffer = past_key != nullptr && past_sequence_length != nullptr; + if (past_key != nullptr && past_sequence_length != nullptr && cache_indirection != nullptr) { + ORT_ENFORCE(past_present_share_buffer); + } + AttentionParameters parameters = {}; - bool past_present_share_buffer = false; ORT_RETURN_IF_ERROR(multihead_attention_helper::CheckInputs(query, key, value, @@ -78,7 +87,8 @@ Status MultiHeadAttention::Compute(OpKernelContext* context) const { attn_bias, past_key, past_value, - nullptr, + cache_indirection, + past_sequence_length, ¶meters, num_heads_, mask_filter_value_, @@ -86,11 +96,24 @@ Status MultiHeadAttention::Compute(OpKernelContext* context) const { is_unidirectional_, past_present_share_buffer, kMultiHeadAttention)); + DUMP_CPU_STRING_INIT(); + DUMP_CPU_STRING("Batch size = ", parameters.batch_size); + DUMP_CPU_STRING("Sequence length = ", parameters.sequence_length); + DUMP_CPU_STRING("Past sequence length = ", parameters.past_sequence_length); + DUMP_CPU_STRING("KV sequence length = ", parameters.kv_sequence_length); + DUMP_CPU_STRING("Total sequence length = ", parameters.total_sequence_length); + DUMP_CPU_STRING("Max sequence length = ", parameters.max_sequence_length); + DUMP_CPU_STRING("Hidden size = ", parameters.hidden_size); + DUMP_CPU_STRING("Head size = ", parameters.head_size); + DUMP_CPU_STRING("Num heads = ", parameters.num_heads); + DUMP_CPU_STRING("Buffer sharing = ", (parameters.past_present_share_buffer == true)); + DUMP_CPU_STRING("QKV format = ", parameters.qkv_format); + DUMP_CPU_STRING("Beam width = ", parameters.beam_width); const int batch_size = parameters.batch_size; const int q_sequence_length = parameters.sequence_length; const int kv_sequence_length = parameters.kv_sequence_length; - const int total_kv_sequence_length = parameters.total_sequence_length; + const int total_sequence_length = parameters.total_sequence_length; int qk_head_size = parameters.head_size; int v_head_size = parameters.v_head_size; int qk_hidden_size = parameters.hidden_size; @@ -106,17 +129,38 @@ Status MultiHeadAttention::Compute(OpKernelContext* context) const { const int k_bias_offset = qk_hidden_size; const int v_bias_offset = 2 * qk_hidden_size; - // If optional outputs aren't needed, present_k and present_v will be null - std::vector present_k_shape({static_cast(batch_size), + // If optional outputs aren't needed, present_key, present_value, and output_qk will be null + std::vector present_key_shape({static_cast(batch_size), + static_cast(num_heads_), + static_cast(parameters.max_sequence_length), + static_cast(qk_head_size)}); + std::vector present_value_shape({static_cast(batch_size), + static_cast(num_heads_), + static_cast(parameters.max_sequence_length), + static_cast(v_head_size)}); + std::vector output_qk_shape({static_cast(batch_size), static_cast(num_heads_), - static_cast(total_kv_sequence_length), - static_cast(qk_head_size)}); - std::vector present_v_shape({static_cast(batch_size), - static_cast(num_heads_), - static_cast(total_kv_sequence_length), - static_cast(v_head_size)}); - Tensor* present_k = context->Output(1, present_k_shape); - Tensor* present_v = context->Output(2, present_v_shape); + static_cast(q_sequence_length), + static_cast(total_sequence_length)}); + Tensor* present_key = context->Output(1, present_key_shape); + Tensor* present_value = context->Output(2, present_value_shape); + Tensor* output_qk = context->Output(3, output_qk_shape); + + bool use_decoder_masked_multihead_attention = false; + if (cache_indirection != nullptr) { + bool use_dmmha_self_attention = parameters.qkv_format == AttentionQkvFormat::Q_K_V_BSNH && + parameters.past_present_share_buffer && + parameters.past_sequence_length > 0; + bool use_dmmha_cross_attention = parameters.qkv_format == AttentionQkvFormat::Q_K_V_BSNH_BNSH_BNSH && + past_key == nullptr && past_value == nullptr && nullptr != past_sequence_length && + parameters.past_sequence_length != *((*past_sequence_length).template Data()); + use_decoder_masked_multihead_attention = !disable_decoder_attention_ && + (use_dmmha_self_attention || use_dmmha_cross_attention) && + parameters.sequence_length == 1 && + parameters.head_size == parameters.v_head_size && + (parameters.mask_type == AttentionMaskType::MASK_2D_KEY_PADDING || parameters.mask_type == AttentionMaskType::MASK_NONE) && + nullptr != past_sequence_length && nullptr != cache_indirection; + } AllocatorPtr allocator; ORT_RETURN_IF_ERROR(context->GetTempSpaceAllocator(&allocator)); @@ -125,15 +169,22 @@ Status MultiHeadAttention::Compute(OpKernelContext* context) const { ORT_RETURN_IF_ERROR(MaybeTransposeToBNSHAndAddBias( context, allocator, batch_size, num_heads_, q_sequence_length, qk_head_size, query, bias, q_bias_offset, Q)); - if (parameters.qkv_format == Q_K_V_BSNH_BNSH_BNSH) { + if (parameters.qkv_format == AttentionQkvFormat::Q_K_V_BSNH_BNSH_BNSH) { // For cross attention with k and v in BNSH format, we assume that bias for key and value are zeros. // So we don't need to add bias for key and value here. assert(past_key == nullptr); assert(past_value == nullptr); + + if (use_decoder_masked_multihead_attention) { + parameters.total_sequence_length = parameters.kv_sequence_length; + parameters.max_sequence_length = parameters.kv_sequence_length; + } + return ApplyAttention(Q.GetMutable()->MutableData(), key->Data(), value->Data(), - key_padding_mask, nullptr /* past */, past_key, past_value, output, present_k, present_v, + key_padding_mask, nullptr /* past */, past_key, past_value, + output, present_key, present_value, output_qk, batch_size, q_sequence_length, kv_sequence_length, qk_head_size, v_head_size, v_hidden_size, attn_bias, context); } @@ -152,8 +203,11 @@ Status MultiHeadAttention::Compute(OpKernelContext* context) const { attn_bias == nullptr && past_key == nullptr && past_value == nullptr && - present_k == nullptr && - present_v == nullptr && + past_sequence_length == nullptr && + cache_indirection == nullptr && + present_key == nullptr && + present_value == nullptr && + output_qk == nullptr && l2_cache_size_ > 0) { MlasFlashAttentionThreadedArgs args; args.batch_size = batch_size; @@ -209,11 +263,42 @@ Status MultiHeadAttention::Compute(OpKernelContext* context) const { return Status::OK(); } + if (use_decoder_masked_multihead_attention) { + // No production use-case will incur this copy cost as the implementation of + // DecoderMaskedMultiHeadAttention is written in such a way that the past and present buffers + // must be shared to have parity in the outputs. + // This is just to circumvent the OpTester's limitation of not being able to bind a specific + // buffer to inputs/outputs. + auto* past_key_data = (past_key == nullptr) ? nullptr : past_key->Data(); + auto* past_value_data = (past_value == nullptr) ? nullptr : past_value->Data(); + auto* present_key_data = (present_key == nullptr) ? nullptr : present_key->MutableData(); + auto* present_value_data = (present_value == nullptr) ? nullptr : present_value->MutableData(); + + if (present_key_data != past_key_data) { + DUMP_CPU_STRING("Copying past_key to present_key for OpTester"); + memcpy(present_key_data, past_key_data, past_key->SizeInBytes()); + } + if (present_value_data != past_value_data) { + DUMP_CPU_STRING("Copying past_value to present_value for OpTester"); + memcpy(present_value_data, past_value_data, past_value->SizeInBytes()); + } + + return ApplyAttentionWithBeams(Q.GetMutable()->MutableData(), + K.GetMutable()->MutableData(), + V.GetMutable()->MutableData(), + key_padding_mask, past_key, past_value, output, present_key, present_value, + batch_size, *((*past_sequence_length).template Data()), parameters.max_sequence_length, + qk_head_size, v_head_size, attn_bias, parameters.broadcast_attn_bias_dim_0, + parameters.broadcast_attn_bias_dim_1, cache_indirection, context, + parameters.beam_width, output_qk); + } + // Compute the attention score and apply the score to V return ApplyAttention(Q.GetMutable()->MutableData(), K.GetMutable()->MutableData(), V.GetMutable()->MutableData(), - key_padding_mask, nullptr /* past */, past_key, past_value, output, present_k, present_v, + key_padding_mask, nullptr /* past */, past_key, past_value, + output, present_key, present_value, output_qk, batch_size, q_sequence_length, kv_sequence_length, qk_head_size, v_head_size, v_hidden_size, attn_bias, context); } diff --git a/onnxruntime/contrib_ops/cpu/bert/multihead_attention.h b/onnxruntime/contrib_ops/cpu/bert/multihead_attention.h index 8a9bef1b2bf0d..a420b6a526882 100644 --- a/onnxruntime/contrib_ops/cpu/bert/multihead_attention.h +++ b/onnxruntime/contrib_ops/cpu/bert/multihead_attention.h @@ -20,6 +20,7 @@ class MultiHeadAttention final : public OpKernel, public AttentionCPUBase { float mask_filter_value_; bool is_unidirectional_; bool disable_flash_; + bool disable_decoder_attention_; int l2_cache_size_; }; diff --git a/onnxruntime/contrib_ops/cpu/bert/multihead_attention_helper.h b/onnxruntime/contrib_ops/cpu/bert/multihead_attention_helper.h index 0cfe90963c334..8af6faadd6e92 100644 --- a/onnxruntime/contrib_ops/cpu/bert/multihead_attention_helper.h +++ b/onnxruntime/contrib_ops/cpu/bert/multihead_attention_helper.h @@ -6,6 +6,8 @@ #include "core/common/common.h" #include "core/providers/common.h" #include "contrib_ops/cpu/bert/attention_common.h" +#include "contrib_ops/cpu/bert/attention_parameters.h" +#include "contrib_ops/cpu/utils/dump_tensor.h" namespace onnxruntime { namespace contrib { @@ -153,7 +155,7 @@ Status CheckPast(const T* past_key, const T* past_value, const T* past_seq_len, } if (past_key_dims[2] != past_value_dims[2]) { return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "Input 'past_key' and 'past_value' shall have same dim 2 (past_sequence_length). ", + "Input 'past_key' and 'past_value' shall have same dim 2 (past_sequence_length or max_sequence_length). ", past_key_dims[2], " vs ", past_value_dims[2]); } if (past_key_dims[3] != head_size) { @@ -233,6 +235,35 @@ AttentionMaskType GetMaskType(const T* key_padding_mask, int batch_size, int seq return mask_type; } +inline Status CheckCacheIndirection( + const gsl::span& cache_indir_dims, int batch_beam_size, int& num_beams, int max_sequence_length) { + if (cache_indir_dims.size() != 3) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Input 'cache_indirection' is expected to have 3 dimensions, got ", + cache_indir_dims.size()); + } + num_beams = static_cast(cache_indir_dims[1]); + if (cache_indir_dims[1] == 0) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Input 'cache_indirection' dimension 1 should be num_beams, got ", + cache_indir_dims[1]); + } + if (cache_indir_dims[0] != static_cast(batch_beam_size / num_beams)) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Input 'cache_indirection' dimension 0 should be batch_size, got ", + cache_indir_dims[0]); + } + if (max_sequence_length > 0 && cache_indir_dims[2] != static_cast(max_sequence_length)) { + // First condition is to avoid this check for cross attention layers where + // past key/past value are passed directly into key/value (which means + // that max_sequence_length = 0) + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Input 'cache_indirection' dimension 2 should be same as (or less than) max_sequence_length, got ", + cache_indir_dims[2]); + } + return Status::OK(); +} + template Status CheckInputs(const T* query, const T* key, @@ -242,6 +273,7 @@ Status CheckInputs(const T* query, const T* attention_bias, const T* past_key, const T* past_value, + const T* cache_indirection, const T* past_seq_len, void* parameters, int num_heads, @@ -263,6 +295,7 @@ Status CheckInputs(const T* query, // L: kv_sequence_length // T: total_sequence_length = P + L // M: max_sequence_length of kv cache when past and present share buffer + // W: beam_width // --------------------------------------------------------------- // MultiHeadAttention inputs: // --------------------------------------------------------------- @@ -308,7 +341,8 @@ Status CheckInputs(const T* query, // Other inputs: // bias (Q/K/V) : None or (3 * D) // key_padding_mask (K/V) : None or (B, T) - // attention_bias : (1, N, S, T), or (B, N, S, T) where only 1 x N x S x T data is used in CUDA. + // attention_bias : (B, N, S, T), (1, N, S, T), (B, 1, S, T) or (1, 1, S, T) + // cache_indirection : (B, W, M) // // The following inputs are not used in cross attention (so they are None for cross attention): // past_key : (B, N, P, H), or (B, N, M, H) when past_present_share_buffer is True. @@ -408,6 +442,13 @@ Status CheckInputs(const T* query, assert(qkv_format != UNKNOWN); + gsl::span cache_indir_dims; + int num_beams = 0; + if (cache_indirection != nullptr) { + cache_indir_dims = cache_indirection->Shape().GetDims(); + ORT_RETURN_IF_ERROR(CheckCacheIndirection(cache_indir_dims, batch_size, num_beams, max_sequence_length)); + } + if (parameters != nullptr) { AttentionParameters* output_parameters = reinterpret_cast(parameters); output_parameters->batch_size = batch_size; @@ -430,6 +471,7 @@ Status CheckInputs(const T* query, output_parameters->broadcast_attn_bias_dim_0 = attention_bias_dims.size() > 0 && attention_bias_dims[0] == 1; output_parameters->broadcast_attn_bias_dim_1 = attention_bias_dims.size() > 1 && attention_bias_dims[1] == 1; output_parameters->qkv_format = qkv_format; + output_parameters->beam_width = num_beams; } return Status::OK(); @@ -444,6 +486,7 @@ Status CheckInputs(const T* query, const T* attention_bias, const T* past_key, const T* past_value, + const T* cache_indirection, const T* past_seq_len, void* parameters, int num_heads, @@ -457,7 +500,7 @@ Status CheckInputs(const T* query, return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "num_heads should be no larger than ", max_threads_per_block); } - return CheckInputs(query, key, value, bias, key_padding_mask, attention_bias, past_key, past_value, + return CheckInputs(query, key, value, bias, key_padding_mask, attention_bias, past_key, past_value, cache_indirection, past_seq_len, parameters, num_heads, mask_filter_value, scale, is_unidirectional, past_present_share_buffer, operator_type); } diff --git a/onnxruntime/contrib_ops/cpu/bert/rotary_helper.h b/onnxruntime/contrib_ops/cpu/bert/rotary_helper.h index 714d962dfb34e..43415d6053fbb 100644 --- a/onnxruntime/contrib_ops/cpu/bert/rotary_helper.h +++ b/onnxruntime/contrib_ops/cpu/bert/rotary_helper.h @@ -5,7 +5,6 @@ #include "core/common/common.h" #include "core/providers/common.h" -#include "contrib_ops/cpu/bert/attention_common.h" namespace onnxruntime { namespace contrib { diff --git a/onnxruntime/contrib_ops/cpu/cpu_contrib_kernels.cc b/onnxruntime/contrib_ops/cpu/cpu_contrib_kernels.cc index c742cd1e95bdd..1a737f3a9d251 100644 --- a/onnxruntime/contrib_ops/cpu/cpu_contrib_kernels.cc +++ b/onnxruntime/contrib_ops/cpu/cpu_contrib_kernels.cc @@ -24,6 +24,7 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, float, GroupQueryAttention); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, MLFloat16, GroupQueryAttention); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, float, SparseAttention); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, MLFloat16, SparseAttention); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, float, RotaryEmbedding); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, MLFloat16, RotaryEmbedding); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, float, Sampling); @@ -37,6 +38,8 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, Fused class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, float, MatMulNBits); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, MLFloat16, MatMulNBits); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, MatMulBnb4); +class ONNX_OPERATOR_TWO_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, uint8_t, int32_t, GatherBlockQuantized); +class ONNX_OPERATOR_TWO_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, uint8_t, int64_t, GatherBlockQuantized); class ONNX_OPERATOR_TWO_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, UInt4x2, int32_t, GatherBlockQuantized); class ONNX_OPERATOR_TWO_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, UInt4x2, int64_t, GatherBlockQuantized); class ONNX_OPERATOR_TWO_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, Int4x2, int32_t, GatherBlockQuantized); @@ -299,6 +302,7 @@ Status RegisterCpuContribKernels(KernelRegistry& kernel_registry) { BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, @@ -316,6 +320,8 @@ Status RegisterCpuContribKernels(KernelRegistry& kernel_registry) { BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, diff --git a/onnxruntime/contrib_ops/cpu/quantization/attention_quant.cc b/onnxruntime/contrib_ops/cpu/quantization/attention_quant.cc index 2c897f183164f..d369939a861d2 100644 --- a/onnxruntime/contrib_ops/cpu/quantization/attention_quant.cc +++ b/onnxruntime/contrib_ops/cpu/quantization/attention_quant.cc @@ -289,7 +289,7 @@ Status QAttention::Compute(OpKernelContext* context) const { // Compute the attention score and apply the score to V return ApplyAttention(Q, K, V, mask_index, past_tensor, nullptr /* past_key */, nullptr /* past_value*/, - output, nullptr /* present_key */, nullptr /* present_value */, + output, nullptr /* present_key */, nullptr /* present_value */, nullptr /* output_qk */, batch_size, sequence_length, sequence_length, head_size, head_size, hidden_size, nullptr /* rel_pos_bias */, context); } diff --git a/onnxruntime/contrib_ops/cpu/quantization/gather_block_quantized.cc b/onnxruntime/contrib_ops/cpu/quantization/gather_block_quantized.cc index 5935663f114a3..b83164d806ffc 100644 --- a/onnxruntime/contrib_ops/cpu/quantization/gather_block_quantized.cc +++ b/onnxruntime/contrib_ops/cpu/quantization/gather_block_quantized.cc @@ -16,6 +16,21 @@ namespace onnxruntime { namespace contrib { +namespace { +template +int32_t GetDataElement(const T1* data_ptr, int64_t data_idx) { + return static_cast(data_ptr[data_idx >> 1].GetElem(narrow(data_idx & 1))); +} + +template <> +int32_t GetDataElement(const uint8_t* data_ptr, int64_t data_idx) { + const uint8_t data_val_u8 = data_ptr[data_idx >> 1]; + // Weights are stored as (nibble2)(nibble1) in uint8_t. + auto data_val = static_cast((data_idx & 1) ? ((data_val_u8 >> 4) & 0x0F) : (data_val_u8 & 0x0F)); + return data_val; +} +} // namespace + template class GatherBlockQuantized : public OpKernel { public: @@ -98,6 +113,12 @@ Status GatherBlockQuantized::PrepareForCompute(OpKernelContext* contex for (int64_t i = p.gather_axis + 1; i < static_cast(data_rank); ++i) shape.push_back(data_shape[narrow(i)]); + // When data is stored as uint8_t, each element has two int4 values. + // The shape in the onnx model reflects that by having the last dimension be half the number of values. + // Ex: For a true data size of 2000x3072, the onnx model would have data of shape 2000x1536. + // However the outputs still need to be of size 2000x3072. Therefore we x2 the last dimension here. + uint32_t components = (std::is_same_v) ? 2 : 1; + shape[shape.size() - 1] = shape.back() * components; p.output_tensor = context->Output(0, TensorShape(std::move(shape))); // validate quantization parameters @@ -106,7 +127,7 @@ Status GatherBlockQuantized::PrepareForCompute(OpKernelContext* contex "data and scales must have the same rank."); for (size_t i = 0; i < data_shape.NumDimensions(); ++i) { ORT_RETURN_IF_NOT(i == static_cast(p.quantize_axis) - ? (data_shape[i] + block_size_ - 1) / block_size_ == scales_shape[i] + ? (data_shape[i] * components + block_size_ - 1) / block_size_ == scales_shape[i] : data_shape[i] == scales_shape[i], "data and scales do not match shapes."); } @@ -165,16 +186,22 @@ Status GatherBlockQuantized::CopyDataAndDequantize(const T1* data_ptr, int64_t output_idx = output_idx_base; int64_t data_idx = data_idx_base; for (int64_t i = 0; i < gather_block; ++i, ++output_idx, ++data_idx) { - auto data_val = static_cast(data_ptr[data_idx >> 1].GetElem(narrow(data_idx & 1))); + auto data_val = GetDataElement(data_ptr, data_idx); int64_t x = data_idx / quantize_full_block; int64_t y = data_idx % quantize_full_block / quantize_N; int64_t z = data_idx % quantize_N; int64_t scale_idx = x * scale_full_block + y / block_size_ * quantize_N + z; auto scale_val = static_cast(scales_ptr[scale_idx]); - auto zp_val = static_cast(zero_points_ptr - ? zero_points_ptr[scale_idx >> 1].GetElem(narrow(scale_idx & 1)) - : 0); + int32_t zp_val; + if constexpr (std::is_same_v) { + // The default zero point for uint8 weights as stored by MatMulNBits op is 8. + zp_val = 8; + } else { + zp_val = static_cast(zero_points_ptr + ? zero_points_ptr[scale_idx >> 1].GetElem(narrow(scale_idx & 1)) + : 0); + } output_ptr[output_idx] = static_cast(static_cast(data_val - zp_val) * scale_val); } @@ -205,7 +232,7 @@ template Status GatherBlockQuantized::Compute(OpKernelContext* context) const { Prepare p; ORT_RETURN_IF_ERROR(PrepareForCompute(context, p)); - + auto components = (std::is_same_v) ? 2 : 1; const auto& data_shape = p.data_tensor->Shape(); // re-shape the data tensor to [gather_M, gather_axis_dim, gather_block] // re-shape the indices tensor to [gather_N] @@ -215,7 +242,7 @@ Status GatherBlockQuantized::Compute(OpKernelContext* context) const { // 2> block is picked from data based on value from indices: axis_i = indices[blk_i % gather_N], // 3> get the corresponding block in data tensor: data_blk = data[blk_i / gather_N, axis_i, :], // 4> pick the element from the block: value_i = data_blk[blk_ele_i] - const int64_t gather_block = data_shape.SizeFromDimension(SafeInt(p.gather_axis) + 1); + const int64_t gather_block = data_shape.SizeFromDimension(SafeInt(p.gather_axis) + 1) * components; const int64_t gather_axis_dim = data_shape[narrow(p.gather_axis)]; const int64_t gather_M = data_shape.SizeToDimension(narrow(p.gather_axis)); const int64_t gather_N = p.indices_tensor->Shape().Size(); @@ -229,7 +256,7 @@ Status GatherBlockQuantized::Compute(OpKernelContext* context) const { // data_i % (quantize_axis_dim * quantize_N) / quantize_N, // data_i % quantize_N) // 4> get scale index: (x, y / block_size_, z) - const int64_t quantize_axis_dim = data_shape[narrow(p.quantize_axis)]; + const int64_t quantize_axis_dim = data_shape[narrow(p.quantize_axis)] * components; const int64_t quantize_N = data_shape.SizeFromDimension(SafeInt(p.quantize_axis) + 1); concurrency::ThreadPool* tp = context->GetOperatorThreadPool(); @@ -273,6 +300,8 @@ Status GatherBlockQuantized::Compute(OpKernelContext* context) const { .TypeConstraint("Tind", DataTypeImpl::GetTensorType()), \ GatherBlockQuantized); +REGISTER_GATHERBLOCKQUANTIZED(uint8_t, int32_t); +REGISTER_GATHERBLOCKQUANTIZED(uint8_t, int64_t); REGISTER_GATHERBLOCKQUANTIZED(UInt4x2, int32_t); REGISTER_GATHERBLOCKQUANTIZED(UInt4x2, int64_t); REGISTER_GATHERBLOCKQUANTIZED(Int4x2, int32_t); diff --git a/onnxruntime/contrib_ops/cpu/quantization/matmul_nbits.cc b/onnxruntime/contrib_ops/cpu/quantization/matmul_nbits.cc index c3e43f897c509..d5a6a1ae699d9 100644 --- a/onnxruntime/contrib_ops/cpu/quantization/matmul_nbits.cc +++ b/onnxruntime/contrib_ops/cpu/quantization/matmul_nbits.cc @@ -133,6 +133,7 @@ class MatMulNBits final : public OpKernel { const size_t nbits_; const bool has_g_idx_; const bool has_bias_; + bool scales_are_packed_{false}; const MLAS_QNBIT_GEMM_COMPUTE_TYPE compute_type_; bool has_unquantized_zero_point_{false}; const bool column_wise_quant_{true}; @@ -181,13 +182,18 @@ Status MatMulNBits::PrePack(const Tensor& tensor, int input_idx, /*out*/ All return Status::OK(); } if (input_idx == InputIndex::B) { - packed_b_size_ = MlasQNBitGemmPackQuantBDataSize(N_, K_, nbits_, block_size_, compute_type_); + const Tensor* scales = nullptr; + OpKernel::Info().TryGetConstantInput(InputIndex::scales, &scales); + + packed_b_size_ = MlasQNBitGemmPackQuantBDataSize(N_, K_, nbits_, block_size_, has_zp_input_, compute_type_); if (packed_b_size_ == 0) { return Status::OK(); } auto qptr = tensor.DataRaw(); + auto scale_ptr = scales ? scales->DataRaw() : nullptr; packed_b_ = IAllocator::MakeUniquePtr(alloc, packed_b_size_, true); - MlasQNBitGemmPackQuantBData(N_, K_, nbits_, block_size_, compute_type_, qptr, packed_b_.get(), nullptr, has_zp_input_, nullptr, nullptr); + MlasQNBitGemmPackQuantBData(N_, K_, nbits_, block_size_, compute_type_, qptr, packed_b_.get(), scale_ptr, + has_zp_input_, nullptr, nullptr); is_packed = true; } else if (compute_type_ == SQNBIT_CompInt8) { #ifdef MLAS_TARGET_AMD64_IX86 @@ -198,10 +204,17 @@ Status MatMulNBits::PrePack(const Tensor& tensor, int input_idx, /*out*/ All is_packed = false; } else if (input_idx == InputIndex::zero_points && packed_b_ != nullptr) { auto zptr = tensor.Data(); - MlasQNBitGemmPackQuantBData(N_, K_, nbits_, block_size_, compute_type_, nullptr, packed_b_.get(), nullptr, has_zp_input_, zptr, nullptr); + MlasQNBitGemmPackQuantBData(N_, K_, nbits_, block_size_, compute_type_, nullptr, packed_b_.get(), nullptr, + has_zp_input_, zptr, nullptr); is_packed = false; } -#endif // MLAS_TARGET_AMD64_IX86 +#elif defined(MLAS_TARGET_ARM64) + if (input_idx == InputIndex::scales && packed_b_ != nullptr && + MlasQNBitGemmScalesPacked(K_, nbits_, block_size_, compute_type_, has_zp_input_)) { + scales_are_packed_ = true; + is_packed = true; + } +#endif // MLAS_TARGET_ARM64 } return Status::OK(); @@ -236,14 +249,24 @@ Status MatMulNBits::PrePack(const Tensor& tensor, int input_idx, /*ou return Status::OK(); } if (input_idx == InputIndex::B) { - packed_b_size_ = MlasQNBitGemmPackQuantBDataSize(N_, K_, nbits_, block_size_, compute_type_); + const Tensor* scales = nullptr; + OpKernel::Info().TryGetConstantInput(InputIndex::scales, &scales); + if (scales && MlasQNBitGemmScalesPacked(K_, nbits_, block_size_, compute_type_, has_zp_input_)) { + auto sptr = scales->Data(); + auto tensor_size = static_cast(tensor.Shape().Size()); + auto ptr = IAllocator::MakeUniquePtr(alloc, tensor_size, true); + MlasConvertHalfToFloatBuffer(sptr, ptr.get(), tensor_size); + scales_fp32_ = std::move(ptr); + } + + packed_b_size_ = MlasQNBitGemmPackQuantBDataSize(N_, K_, nbits_, block_size_, has_zp_input_, compute_type_); if (packed_b_size_ == 0) { return Status::OK(); } auto qptr = tensor.DataRaw(); packed_b_ = IAllocator::MakeUniquePtr(alloc, packed_b_size_, true); MlasQNBitGemmPackQuantBData(N_, K_, nbits_, block_size_, compute_type_, qptr, packed_b_.get(), - nullptr, has_zp_input_, nullptr, nullptr); + scales_fp32_.get(), has_zp_input_, nullptr, nullptr); is_packed = true; } else if (compute_type_ == SQNBIT_CompInt8) { #ifdef MLAS_TARGET_AMD64_IX86 @@ -287,7 +310,7 @@ Status MatMulNBits::ComputeBPacked(const Tensor* a, concurrency::ThreadPool* thread_pool, const MatMulComputeHelper& helper) const { const auto* a_data = a->Data(); - const auto* scales_data = scales->Data(); + const auto* scales_data = scales == nullptr ? nullptr : scales->Data(); const auto* zero_points_data = zero_points == nullptr ? nullptr : zero_points->DataRaw(); const auto* bias_data = bias == nullptr ? nullptr : bias->Data(); auto* y_data = y->MutableData(); @@ -300,7 +323,7 @@ Status MatMulNBits::ComputeBPacked(const Tensor* a, IAllocatorUniquePtr workspace{}; const size_t workspace_size = MlasQNBitGemmBatchWorkspaceSize( - M, N, K, batch_count, nbits_, block_size_, compute_type_); + M, N, K, batch_count, nbits_, block_size_, zero_points, compute_type_); if (workspace_size > 0) { // Use reserve since no caching is needed workspace = IAllocator::MakeUniquePtr(allocator, workspace_size, true); @@ -310,11 +333,9 @@ Status MatMulNBits::ComputeBPacked(const Tensor* a, for (size_t i = 0; i < batch_count; ++i) { data[i].A = a_data + helper.LeftOffsets()[i]; data[i].lda = lda; -#ifdef MLAS_TARGET_AMD64_IX86 if (compute_type_ == SQNBIT_CompInt8) { data[i].QuantBDataWorkspace = packed_b_.get(); } -#endif data[i].PackedQuantBData = static_cast(packed_b_.get()); data[i].QuantBScale = scales_data; data[i].QuantBZeroPoint = zero_points_data; @@ -351,7 +372,7 @@ Status MatMulNBits::ComputeBPacked(const Tensor* a, IAllocatorUniquePtr workspace{}; const size_t workspace_size = MlasQNBitGemmBatchWorkspaceSize( - M, N, K, batch_count, nbits_, block_size_, compute_type_); + M, N, K, batch_count, nbits_, block_size_, zero_points, compute_type_); if (workspace_size > 0) { // Use reserve since no caching is needed workspace = IAllocator::MakeUniquePtr(allocator, workspace_size, true); @@ -653,7 +674,7 @@ template Status MatMulNBits::Compute(OpKernelContext* ctx) const { concurrency::ThreadPool* thread_pool = ctx->GetOperatorThreadPool(); const Tensor* a = ctx->Input(InputIndex::A); - const Tensor* scales = ctx->Input(InputIndex::scales); + const Tensor* scales = scales_are_packed_ ? nullptr : ctx->Input(InputIndex::scales); const Tensor* zero_points = ctx->Input(InputIndex::zero_points); const Tensor* reorder_idx = ctx->Input(InputIndex::g_idx); const Tensor* bias = ctx->Input(InputIndex::bias); diff --git a/onnxruntime/contrib_ops/cpu/skip_layer_norm_helper.h b/onnxruntime/contrib_ops/cpu/skip_layer_norm_helper.h index 4c901f5650dbd..b70bd317b95b2 100644 --- a/onnxruntime/contrib_ops/cpu/skip_layer_norm_helper.h +++ b/onnxruntime/contrib_ops/cpu/skip_layer_norm_helper.h @@ -5,7 +5,6 @@ #include "core/common/common.h" #include "core/providers/common.h" -#include "contrib_ops/cpu/bert/attention_common.h" namespace onnxruntime { namespace contrib { diff --git a/onnxruntime/contrib_ops/cpu/sparse/sparse_attention.cc b/onnxruntime/contrib_ops/cpu/sparse/sparse_attention.cc index e337f41a8688d..469084e7b4491 100644 --- a/onnxruntime/contrib_ops/cpu/sparse/sparse_attention.cc +++ b/onnxruntime/contrib_ops/cpu/sparse/sparse_attention.cc @@ -21,16 +21,20 @@ using onnxruntime::concurrency::ThreadPool; namespace onnxruntime { namespace contrib { -ONNX_OPERATOR_TYPED_KERNEL_EX( - SparseAttention, - kMSDomain, - 1, - float, - kCpuExecutionProvider, - KernelDefBuilder() - .TypeConstraint("T", DataTypeImpl::GetTensorType()) - .TypeConstraint("M", DataTypeImpl::GetTensorType()), - SparseAttention); +#define REGISTER_KERNEL_TYPED(T) \ + ONNX_OPERATOR_TYPED_KERNEL_EX( \ + SparseAttention, \ + kMSDomain, \ + 1, \ + T, \ + kCpuExecutionProvider, \ + KernelDefBuilder() \ + .TypeConstraint("T", DataTypeImpl::GetTensorType()) \ + .TypeConstraint("M", DataTypeImpl::GetTensorType()), \ + SparseAttention); + +REGISTER_KERNEL_TYPED(float) +REGISTER_KERNEL_TYPED(MLFloat16) template SparseAttention::SparseAttention(const OpKernelInfo& info) : OpKernel(info), SparseAttentionBase(info) { diff --git a/onnxruntime/contrib_ops/cpu/sparse/sparse_attention_base.h b/onnxruntime/contrib_ops/cpu/sparse/sparse_attention_base.h index 37172074e5d86..cccaec0b16ce5 100644 --- a/onnxruntime/contrib_ops/cpu/sparse/sparse_attention_base.h +++ b/onnxruntime/contrib_ops/cpu/sparse/sparse_attention_base.h @@ -4,12 +4,13 @@ #pragma once #include "contrib_ops/cpu/bert/attention_helper.h" +#include "contrib_ops/cpu/bert/attention_common.h" +#include "contrib_ops/cpu/bert/attention_parameters.h" +#include "contrib_ops/cpu/utils/dump_tensor.h" #include "core/common/common.h" -#include "contrib_ops/cpu/bert/attention_common.h" #include "core/common/safeint.h" #include "core/framework/op_kernel.h" -#include "contrib_ops/cpu/utils/dump_tensor.h" namespace onnxruntime { namespace contrib { @@ -66,7 +67,10 @@ class SparseAttentionBase { int present_buffer_sequence_length = static_cast(present_key->Shape().GetDims()[2]); // Allocate a buffer to store Softmax(QK) - size_t bytes = SafeInt(batch_size) * num_heads_ * sequence_length * parameters.total_sequence_length * sizeof(T); + bool attention_mlas_supported = MlasGQASupported(CblasNoTrans, CblasTrans) && + MlasGQASupported(CblasNoTrans, CblasNoTrans); + size_t bytes = SafeInt(batch_size) * num_heads_ * sequence_length * parameters.total_sequence_length * + (attention_mlas_supported ? sizeof(T) : sizeof(float)); auto attention_probs = allocator->Alloc(bytes); BufferUniquePtr scratch_buffer(attention_probs, BufferDeleter(allocator)); @@ -76,21 +80,37 @@ class SparseAttentionBase { auto* tp = context->GetOperatorThreadPool(); const T* k = packed_qkv ? Q + num_heads_ * sequence_length * head_size : K; - ComputeAttentionProbs( - static_cast(attention_probs), Q, k, total_key_lengths->Data(), - batch_size, sequence_length, parameters.total_sequence_length, - past_buffer_sequence_length, present_buffer_sequence_length, head_size, - past_key->Data(), present_key->MutableData(), past_present_share_buffer, packed_qkv, - block_row_indices->Data(), block_col_indices->Data(), parameters, tp); - - // Compute the attentionScore * Value: out(B, N, S, H_v) = attention_probs(B, N, S, T) x V(B, N, T, H_v) const T* v = packed_qkv ? Q + (num_heads_ + kv_num_heads_) * sequence_length * head_size : V; - ComputeVxAttentionScore( - output->MutableData(), static_cast(attention_probs), v, - total_key_lengths->Data(), - batch_size, sequence_length, parameters.total_sequence_length, - past_buffer_sequence_length, present_buffer_sequence_length, head_size, parameters.hidden_size, - past_value->Data(), present_value->MutableData(), past_present_share_buffer, packed_qkv, tp); + + if (attention_mlas_supported) { + ComputeAttentionProbs( + static_cast(attention_probs), Q, k, total_key_lengths->Data(), + batch_size, sequence_length, parameters.total_sequence_length, + past_buffer_sequence_length, present_buffer_sequence_length, head_size, + past_key->Data(), present_key->MutableData(), past_present_share_buffer, packed_qkv, + block_row_indices->Data(), block_col_indices->Data(), parameters, tp, allocator); + + ComputeVxAttentionScore( + output->MutableData(), static_cast(attention_probs), v, + total_key_lengths->Data(), + batch_size, sequence_length, parameters.total_sequence_length, + past_buffer_sequence_length, present_buffer_sequence_length, head_size, parameters.hidden_size, + past_value->Data(), present_value->MutableData(), past_present_share_buffer, packed_qkv, tp, allocator); + } else { + ComputeAttentionProbs( + static_cast(attention_probs), Q, k, total_key_lengths->Data(), + batch_size, sequence_length, parameters.total_sequence_length, + past_buffer_sequence_length, present_buffer_sequence_length, head_size, + past_key->Data(), present_key->MutableData(), past_present_share_buffer, packed_qkv, + block_row_indices->Data(), block_col_indices->Data(), parameters, tp, allocator); + + ComputeVxAttentionScore( + output->MutableData(), static_cast(attention_probs), v, + total_key_lengths->Data(), + batch_size, sequence_length, parameters.total_sequence_length, + past_buffer_sequence_length, present_buffer_sequence_length, head_size, parameters.hidden_size, + past_value->Data(), present_value->MutableData(), past_present_share_buffer, packed_qkv, tp, allocator); + } return Status::OK(); } @@ -99,9 +119,9 @@ class SparseAttentionBase { // Helper function to compute the attention probs. It does 2 things: // attention_probs(B, N, S, T) = 1/sqrt(H) x Q(B, N, S, H) x K'(B, N, T, H -> B, N, H, T) // attention_probs(B, N, S, T) = Softmax(attention_probs) - template + template void ComputeAttentionProbs( - T* attention_probs, // output buffer with size BxNxSxT + U* attention_probs, // output buffer with size BxNxSxT const T* Q, // query start pointer const T* K, // key start pointer const int32_t* total_key_lengths, // total key sequence lengths (past + new) @@ -118,7 +138,8 @@ class SparseAttentionBase { const int32_t* block_row_indices, // block row indices const int32_t* block_col_indices, // block column indices SparseAttentionParameters& parameters, // parameters - ThreadPool* tp) const { // thread pool + ThreadPool* tp, // thread pool + AllocatorPtr allocator) const { const bool is_prompt = (total_sequence_length == sequence_length); const ptrdiff_t packed_batch_stride = packed_qkv ? SafeInt(num_heads_ + 2 * kv_num_heads_) * sequence_length * head_size @@ -159,11 +180,11 @@ class SparseAttentionBase { int nonzero_elements = block_row_indices[(layout_index + 1) * parameters.stride_row_indices - 1]; int dense_nonzero = (parameters.stride_row_indices * (parameters.stride_row_indices - 1)) / 2; layout_has_sparse[layout_index] = nonzero_elements < dense_nonzero; - DUMP_STRING("layout_has_sparse[", layout_index, "]=", layout_has_sparse[layout_index]); + DUMP_CPU_STRING("layout_has_sparse[", layout_index, "]=", layout_has_sparse[layout_index]); } ThreadPool::TryParallelFor(tp, loop_len, unit_cost, [&](std::ptrdiff_t begin, std::ptrdiff_t end) { - DUMP_STRING("batch_size=", batch_size, ",num_heads=", num_heads_, ",loop_len=", loop_len, ",begin=", begin, ",end=", end); + DUMP_CPU_STRING("batch_size=", batch_size, ",num_heads=", num_heads_, ",loop_len=", loop_len, ",begin=", begin, ",end=", end); for (std::ptrdiff_t i = begin; i != end; ++i) { const int batch_index = static_cast(i) / num_heads_; const int head_index = static_cast(i) % num_heads_; @@ -172,7 +193,7 @@ class SparseAttentionBase { const int total_seq_len = total_key_lengths[batch_index]; const ptrdiff_t output_offset = SafeInt(i) * sequence_length * total_sequence_length; - T* output = attention_probs + output_offset; + U* output = attention_probs + output_offset; const T* k; if (packed_qkv) { @@ -199,31 +220,55 @@ class SparseAttentionBase { q = Q + q_input_chunk_length * i; } - DUMP_STRING("i=", i, ",batch_index=", batch_index, ",head_index=", head_index, - ",past_seq_len=", past_seq_len, ",total_seq_len=", total_seq_len, ",packed_qkv=", packed_qkv); + DUMP_CPU_STRING("i=", i, ",batch_index=", batch_index, ",head_index=", head_index, + ",past_seq_len=", past_seq_len, ",total_seq_len=", total_seq_len, ",packed_qkv=", packed_qkv); DUMP_CPU_TENSOR("Q", q, sequence_length, head_size); DUMP_CPU_TENSOR("K", k, total_seq_len, head_size); - math::GemmEx(CblasNoTrans, CblasTrans, sequence_length, total_seq_len, head_size, alpha, q, - head_size, k, head_size, 0.0f /*bata*/, output, total_seq_len, - nullptr); + if constexpr (std::is_same::value) { + math::GemmEx(CblasNoTrans, CblasTrans, sequence_length, total_seq_len, head_size, alpha, q, + head_size, k, head_size, 0.0f /*bata*/, output, total_seq_len, + nullptr); + } else if constexpr (std::is_same::value) { + MlasGemm(CblasNoTrans, CblasTrans, sequence_length, total_seq_len, head_size, + q, head_size, k, head_size, output, total_seq_len, + MLFloat16(alpha).val, static_cast(0) /*beta*/, nullptr); + } else { + size_t bytes = static_cast(head_size) * (sequence_length + total_seq_len) * sizeof(float); + auto q_k_fp32 = allocator->Alloc(bytes); + BufferUniquePtr scratch_buffer(q_k_fp32, BufferDeleter(allocator)); + + float* q_fp32 = static_cast(q_k_fp32); + MlasConvertHalfToFloatBuffer(q, q_fp32, static_cast(head_size) * sequence_length); + + float* k_fp32 = q_fp32 + head_size * sequence_length; + MlasConvertHalfToFloatBuffer(k, k_fp32, static_cast(head_size) * total_seq_len); + + math::GemmEx(CblasNoTrans, CblasTrans, sequence_length, total_seq_len, head_size, + alpha, q_fp32, head_size, k_fp32, head_size, 0.0f /*bata*/, + output, total_seq_len, nullptr); + } DUMP_CPU_TENSOR("QK", output, sequence_length, total_seq_len); // Compute Softmax for causal and output result in place. - T* output_softmax = output; + U* output_softmax = output; int layout_id = head_index % parameters.num_sparse_layout; bool is_sparse_layout = layout_has_sparse[layout_id]; - DUMP_STRING("layout_id=", layout_id, ",is_sparse_layout=", is_sparse_layout); + DUMP_CPU_STRING("layout_id=", layout_id, ",is_sparse_layout=", is_sparse_layout); if (!is_sparse_layout) { // dense for (int q_id = 0; q_id < sequence_length; q_id++) { int causal_length = past_seq_len + q_id + 1; ComputeAttentionSoftmaxInplace(output_softmax, 1, causal_length, nullptr); for (int remain_seq_id = causal_length; remain_seq_id < total_seq_len; remain_seq_id++) { - output_softmax[remain_seq_id] = 0.f; + if constexpr (std::is_same::value) { + output_softmax[remain_seq_id] = 0.f; + } else { + output_softmax[remain_seq_id] = MLFloat16::FromBits(static_cast(0)); + } } output_softmax += total_seq_len; } @@ -246,19 +291,19 @@ class SparseAttentionBase { int nonzero_blocks = end_in_col_indices - start_in_col_indices; has_sparse = (nonzero_blocks != row_in_sparse_layout + 1); - DUMP_STRING("q_id=", q_id, - ",q_abs_position=", q_abs_position, - ",sparse_block_size=", parameters.sparse_block_size, - ",row_in_sparse_layout=", row_in_sparse_layout, - ",start_in_col_indices=", start_in_col_indices, - ",end_in_col_indices=", end_in_col_indices, - ",nonzero_blocks=", nonzero_blocks, - ",has_sparse=", has_sparse); + DUMP_CPU_STRING("q_id=", q_id, + ",q_abs_position=", q_abs_position, + ",sparse_block_size=", parameters.sparse_block_size, + ",row_in_sparse_layout=", row_in_sparse_layout, + ",start_in_col_indices=", start_in_col_indices, + ",end_in_col_indices=", end_in_col_indices, + ",nonzero_blocks=", nonzero_blocks, + ",has_sparse=", has_sparse); // Expand attention mask for current row of q_id if (has_sparse) { int block_aligned_length = q_abs_position / parameters.sparse_block_size * parameters.sparse_block_size + parameters.sparse_block_size; - DUMP_STRING("block_aligned_length=", block_aligned_length); + DUMP_CPU_STRING("block_aligned_length=", block_aligned_length); std::fill_n(mask.begin(), block_aligned_length, 0); for (int j = start_in_col_indices; j < end_in_col_indices; j++) { @@ -277,14 +322,23 @@ class SparseAttentionBase { // Update inline according to attention mask. if (has_sparse) { for (int s = 0; s < causal_length; s++) { - if (mask[s] == 0) - output_softmax[s] = std::numeric_limits::lowest(); + if (mask[s] == 0) { + if constexpr (std::is_same::value) { + output_softmax[s] = std::numeric_limits::lowest(); + } else { + output_softmax[s] = MLFloat16::FromBits(static_cast(0xFBFF)); + } + } } } ComputeAttentionSoftmaxInplace(output_softmax, 1, causal_length, nullptr); for (int remain_seq_id = causal_length; remain_seq_id < total_seq_len; remain_seq_id++) { - output_softmax[remain_seq_id] = 0.f; + if constexpr (std::is_same::value) { + output_softmax[remain_seq_id] = 0.f; + } else { + output_softmax[remain_seq_id] = MLFloat16::FromBits(static_cast(0)); + } } output_softmax += total_seq_len; @@ -298,9 +352,9 @@ class SparseAttentionBase { }); } - template + template void ComputeVxAttentionScore(T* output, // buffer for the result with size BxSxNxH - const T* attention_probs, // Softmax of Q*K' with size BxNxSxT + const U* attention_probs, // Softmax of Q*K' with size BxNxSxT const T* V, // v value with size BxN_kvxSxH const int32_t* total_key_lengths, // total sequence lengths int batch_size, // batch size @@ -314,7 +368,8 @@ class SparseAttentionBase { T* present_value, // present value only bool past_present_share_buffer, // whether past_key and present_key share the buffer bool packed_qkv, // whether Q, K, V are packed - ThreadPool* tp) const { + ThreadPool* tp, + AllocatorPtr allocator) const { const bool is_prompt = sequence_length == total_sequence_length; const ptrdiff_t packed_batch_stride = packed_qkv ? SafeInt(num_heads_ + 2 * kv_num_heads_) * sequence_length * head_size @@ -340,11 +395,18 @@ class SparseAttentionBase { unit_cost.bytes_stored += bytes_to_copy_value; } + size_t output_fp32_bytes = 0; + if constexpr (std::is_same::value && std::is_same::value) { + output_fp32_bytes = SafeInt(sequence_length) * batch_size * num_heads_ * head_size * sizeof(float); + } + auto output_fp32 = allocator->Alloc(output_fp32_bytes); + BufferUniquePtr scratch_buffer(output_fp32, BufferDeleter(allocator)); + DUMP_CPU_TENSOR_INIT(); ThreadPool::TryParallelFor( tp, SafeInt(batch_size) * num_heads_, unit_cost, [&](std::ptrdiff_t begin, std::ptrdiff_t end) { - DUMP_STRING("batch_size=", batch_size, ",num_heads=", num_heads_, ",begin=", begin, ",end=", end); + DUMP_CPU_STRING("batch_size=", batch_size, ",num_heads=", num_heads_, ",begin=", begin, ",end=", end); for (std::ptrdiff_t i = begin; i != end; ++i) { const int batch_index = static_cast(i / num_heads_); @@ -353,8 +415,8 @@ class SparseAttentionBase { const size_t past_chunk_length = static_cast(past_seq_len) * head_size; const int total_seq_len = total_key_lengths[batch_index]; - DUMP_STRING("i=", i, ",batch_index=", batch_index, ",head_index=", head_index, - ",past_seq_len=", past_seq_len, ",total_seq_len=", total_seq_len, ",packed_qkv=", packed_qkv); + DUMP_CPU_STRING("i=", i, ",batch_index=", batch_index, ",head_index=", head_index, + ",past_seq_len=", past_seq_len, ",total_seq_len=", total_seq_len, ",packed_qkv=", packed_qkv); const T* v; if (packed_qkv) { @@ -375,14 +437,42 @@ class SparseAttentionBase { DUMP_CPU_TENSOR("attention_probs", attention_probs + attention_probs_offset, sequence_length, total_seq_len); - math::GemmEx(CblasNoTrans, CblasNoTrans, sequence_length, head_size, total_seq_len, - 1.f, /*alpha*/ - attention_probs + attention_probs_offset, total_seq_len, v, - head_size, 0.0f /*beta*/, output_current, hidden_size, nullptr); + if constexpr (std::is_same::value) { + math::GemmEx(CblasNoTrans, CblasNoTrans, sequence_length, head_size, total_seq_len, + 1.f, /*alpha*/ + attention_probs + attention_probs_offset, total_seq_len, v, + head_size, 0.0f /*beta*/, output_current, hidden_size, nullptr); + } else if constexpr (std::is_same::value) { + MlasGemm(CblasNoTrans, CblasNoTrans, sequence_length, head_size, total_seq_len, + attention_probs + attention_probs_offset, total_seq_len, + v, head_size, output_current, hidden_size, + MLFloat16(1.0f).val, static_cast(0) /*beta*/, nullptr); + } else { + size_t bytes = static_cast(head_size) * total_seq_len * sizeof(float); + auto v_fp32 = allocator->Alloc(bytes); + BufferUniquePtr scratch_buffer(v_fp32, BufferDeleter(allocator)); + + float* v_fp32_ptr = static_cast(v_fp32); + MlasConvertHalfToFloatBuffer(v, v_fp32_ptr, static_cast(head_size) * total_seq_len); + + float* output_fp32_current = static_cast(output_fp32) + + (batch_index * sequence_length * num_heads_ + head_index) * head_size; + math::GemmEx(CblasNoTrans, CblasNoTrans, sequence_length, head_size, total_seq_len, + 1.f, /*alpha*/ attention_probs + attention_probs_offset, + total_seq_len, v_fp32_ptr, + head_size, 0.0f /*beta*/, output_fp32_current, + hidden_size, nullptr); + } DUMP_CPU_TENSOR("out", attention_probs + attention_probs_offset, sequence_length, head_size); } }); + + if constexpr (std::is_same::value && std::is_same::value) { + MlasConvertFloatToHalfBuffer(static_cast(output_fp32), + output, + SafeInt(sequence_length) * batch_size * num_heads_ * head_size); + } } }; diff --git a/onnxruntime/contrib_ops/cpu/sparse/sparse_attention_helper.h b/onnxruntime/contrib_ops/cpu/sparse/sparse_attention_helper.h index ca69370b4ce17..dfb60f635bc33 100644 --- a/onnxruntime/contrib_ops/cpu/sparse/sparse_attention_helper.h +++ b/onnxruntime/contrib_ops/cpu/sparse/sparse_attention_helper.h @@ -6,6 +6,7 @@ #include "core/common/common.h" #include "core/providers/common.h" #include "contrib_ops/cpu/bert/attention_common.h" +#include "contrib_ops/cpu/bert/attention_parameters.h" namespace onnxruntime { namespace contrib { diff --git a/onnxruntime/contrib_ops/cpu/transformers/beam_search.cc b/onnxruntime/contrib_ops/cpu/transformers/beam_search.cc index 12fae5ccf0983..885827fb09e7e 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/beam_search.cc +++ b/onnxruntime/contrib_ops/cpu/transformers/beam_search.cc @@ -68,6 +68,10 @@ REGISTER_KERNEL_TYPED(float) namespace transformers { +constexpr const char* kBeamSearchNotSupportFp16InCpu = + "BeamSearch does not support float16 model on CPU execution provider. " + "Use float32 model or CUDA execution provider instead."; + void BeamSearch::Init(const OpKernelInfo& info) { parameters_->ParseFromAttributes(info); @@ -139,13 +143,19 @@ Status BeamSearch::SetupSubgraphExecutionInfo(const SessionState& session_state, ORT_RETURN_IF_ERROR(t5_encoder_subgraph_->Setup(session_state, subgraph_session_state)); encoder_feeds_fetches_manager_ = t5_encoder_subgraph_->GetFeedsFetchesManager(); - if (parameters_->decoder_start_token_id < 0) { - ORT_RETURN_IF(t5_encoder_subgraph_->num_subgraph_inputs != 2, - "Encoder subgraph shall have 2 inputs when decoder_start_token_id attribute is empty"); + if (!t5_encoder_subgraph_->HasLogitsOutput()) { + // New format requires start token id. + ORT_ENFORCE(parameters_->decoder_start_token_id >= 0); } else { - ORT_RETURN_IF(t5_encoder_subgraph_->num_subgraph_inputs != 3, - "Encoder subgraph shall have 3 inputs when decoder_start_token_id attribute is available"); + if (parameters_->decoder_start_token_id < 0) { + ORT_RETURN_IF(t5_encoder_subgraph_->num_subgraph_inputs != 2, + "Encoder subgraph shall have 2 inputs when decoder_start_token_id attribute is empty"); + } else { + ORT_RETURN_IF(t5_encoder_subgraph_->num_subgraph_inputs != 3, + "Encoder subgraph shall have 3 inputs when decoder_start_token_id attribute is available"); + } } + } else if (attribute_name == "decoder") { ORT_ENFORCE(t5_decoder_subgraph_ == nullptr, "SetupSubgraphExecutionInfo should only be called once for each subgraph."); @@ -209,6 +219,8 @@ Status BeamSearch::Compute(OpKernelContext* ctx) const { // Make a copy of parameters since we will update it based on inputs later BeamSearchParameters parameters = *parameters_; + const bool is_cpu_provider = ctx->GetComputeStream() == nullptr; + if (parameters.model_type == IGenerationParameters::kModelTypeGpt) { if (!gpt_subgraph_->IsOutputFloat16()) { // Output float32 BeamSearchGpt impl{ @@ -234,6 +246,10 @@ Status BeamSearch::Compute(OpKernelContext* ctx) const { return impl.Execute(init_run_decoder_feeds_fetches_manager_, *decoder_feeds_fetches_manager_); } else { // Output float16 + if (is_cpu_provider) { + ORT_THROW(kBeamSearchNotSupportFp16InCpu); + } + BeamSearchGpt impl{ *ctx_internal, has_init_decoder_ ? init_run_decoder_session_state : nullptr, @@ -250,6 +266,7 @@ Status BeamSearch::Compute(OpKernelContext* ctx) const { device_copy_int32_func_, update_gpt_feeds_fp16_func_, create_beam_scorer_func_}; + #ifdef USE_CUDA ORT_RETURN_IF_ERROR(impl.InitializeCuda(reorder_past_state_func_, cuda_device_prop_, cuda_device_arch_)); #endif @@ -288,6 +305,10 @@ Status BeamSearch::Compute(OpKernelContext* ctx) const { return impl.Execute(*encoder_feeds_fetches_manager_, *decoder_feeds_fetches_manager_); } else { + if (is_cpu_provider) { + ORT_THROW(kBeamSearchNotSupportFp16InCpu); + } + BeamSearchT5 impl{ *ctx_internal, *encoder_session_state, *decoder_session_state, *t5_encoder_subgraph_, *t5_decoder_subgraph_, thread_pool, ctx->GetComputeStream(), dumper_, parameters, @@ -303,6 +324,7 @@ Status BeamSearch::Compute(OpKernelContext* ctx) const { expand_buffer_float_func_, expand_buffer_float16_func_, create_beam_scorer_func_}; + #ifdef USE_CUDA ORT_RETURN_IF_ERROR(impl.InitializeCuda(reorder_past_state_func_, init_cache_indir_func_, cuda_device_prop_, cuda_device_arch_)); #endif @@ -340,6 +362,10 @@ Status BeamSearch::Compute(OpKernelContext* ctx) const { return impl.Execute(*encoder_feeds_fetches_manager_, *decoder_feeds_fetches_manager_); } else { + if (is_cpu_provider) { + ORT_THROW(kBeamSearchNotSupportFp16InCpu); + } + BeamSearchWhisper impl{ *ctx_internal, *encoder_session_state, *decoder_session_state, *whisper_encoder_subgraph_, *whisper_decoder_subgraph_, thread_pool, ctx->GetComputeStream(), dumper_, parameters, diff --git a/onnxruntime/contrib_ops/cpu/transformers/beam_search_impl_t5.h b/onnxruntime/contrib_ops/cpu/transformers/beam_search_impl_t5.h index b67d003eaceeb..c9646cf0fab2e 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/beam_search_impl_t5.h +++ b/onnxruntime/contrib_ops/cpu/transformers/beam_search_impl_t5.h @@ -51,7 +51,13 @@ class BeamSearchT5 : public BeamSearchBase { expand_buffer_int32_func_(expand_buffer_int32_func), expand_buffer_float_func_(expand_buffer_float_func), expand_buffer_float16_func_(expand_buffer_float16_func), - create_beam_scorer_func_(create_beam_scorer_func) {} + create_beam_scorer_func_(create_beam_scorer_func) { + // When decoder uses encoder_hidden_state, make sure the encoder outputs it. + if (decoder_subgraph_.UseEncoderHiddenState()) { + ORT_ENFORCE(encoder_subgraph_.subgraph_output_names[1] == "encoder_hidden_states"); + } + ORT_ENFORCE(encoder_subgraph_.num_layers == decoder_subgraph_.num_layers); + } #ifdef USE_CUDA Status InitializeCuda( @@ -160,7 +166,7 @@ Status BeamSearchT5::Execute(const FeedsFetchesManager& encoder_feeds_fetches this->create_encoder_inputs_func_, this->add_to_feeds_func_, buffer, - decoder_input_ids, + decoder_input_ids, // new format does not use decoder_input_ids in encoder, it is still initialized here when decoder_start_token_id >= 0. this->ort_stream_)); #ifdef DEBUG_NODE_INPUTS_OUTPUTS @@ -233,35 +239,47 @@ Status BeamSearchT5::Execute(const FeedsFetchesManager& encoder_feeds_fetches std::vector decoder_fetches; - if (current_length + 1 < parameters->max_length) { + // When encoder outputs logits (in old format), we need get the next token from logits. + if (current_length + 1 < parameters->max_length && encoder_subgraph_.HasLogitsOutput()) { ++iteration_counter; - ORT_RETURN_IF_ERROR(this->GenerateNextToken(encoder_fetches[0], + const OrtValue& logits = encoder_fetches[0]; + ORT_RETURN_IF_ERROR(this->GenerateNextToken(logits, beam_next_tokens, beam_state, cpu_state, iteration_counter)); ++current_length; // Increase sequence length after a new token is generated. + } - ORT_RETURN_IF_ERROR(decoder_subgraph_.CreateInitialFeeds(this->cpu_allocator_, - ReinterpretAsSpan(beam_next_tokens), - this->implicit_inputs_, - encoder_feeds, - encoder_fetches, - decoder_feeds, - this->device_copy_int32_func_, - this->expand_buffer_int32_func_, - this->expand_buffer_float_func_, - this->expand_buffer_float16_func_, - parameters->num_beams, - this->ort_stream_, - decoder_subgraph_.UseSequenceAsInputIds(), - current_length, - cpu_state.sequences, - parameters->max_length, - decoder_subgraph_.has_decoder_masked_attention_, - this->cuda_device_prop_ != nullptr)); + if (current_length < parameters->max_length) { + // when no logits, copy sequence (filled with start token IDs) to input_ids for decoder. + bool copy_sequence_to_input_ids = decoder_subgraph_.UseSequenceAsInputIds() || !encoder_subgraph_.HasLogitsOutput(); + if (copy_sequence_to_input_ids) { + ORT_ENFORCE(current_length == cpu_state.sequences.GetSequenceLength()); + } + + // Generate inputs for next decoder subgraph call. + ORT_RETURN_IF_ERROR(decoder_subgraph_.CreateInitialFeeds( + this->cpu_allocator_, + ReinterpretAsSpan(beam_next_tokens), + this->implicit_inputs_, + encoder_feeds, + encoder_fetches, + decoder_feeds, + this->device_copy_int32_func_, + this->expand_buffer_int32_func_, + this->expand_buffer_float_func_, + this->expand_buffer_float16_func_, + parameters->num_beams, + this->ort_stream_, + copy_sequence_to_input_ids, + cpu_state.sequences, + parameters->max_length, + decoder_subgraph_.has_decoder_masked_attention_, + this->cuda_device_prop_ != nullptr)); if (decoder_subgraph_.past_present_share_buffer_) { + // Configure buffer sharing of past and present kv cache. decoder_fetches.reserve(static_cast(decoder_subgraph_.GetFirstPresentOutputIndex()) + 2 * static_cast(decoder_subgraph_.num_layers)); decoder_fetches.resize(decoder_subgraph_.GetFirstPresentOutputIndex(), OrtValue()); @@ -299,14 +317,19 @@ Status BeamSearchT5::Execute(const FeedsFetchesManager& encoder_feeds_fetches while (current_length < parameters->max_length) { iteration_counter++; + #ifdef DEBUG_GENERATION - auto cur_len = std::to_string(current_length); - dumper->Print("***CurrentLength", cur_len, true); + dumper->Print(::onnxruntime::MakeString("Iteration=", iteration_counter, + ", CurrentLength=", current_length, + ", num_layers=", decoder_subgraph_.num_layers, + ", decoder_feeds=", decoder_feeds.size(), + ", start_token_id=", parameters->decoder_start_token_id)); for (int i = 0; i < decoder_subgraph_.GetFirstPastInputIndex(); i++) { dumper->Print("decoder_feeds", i, true); dumper->Print("", decoder_feeds[i]); } + for (int i = 0; i < decoder_subgraph_.num_layers; i++) { int self_key_idx = decoder_subgraph_.GetFirstPastInputIndex() + 2 * i; int self_value_idx = self_key_idx + 1; diff --git a/onnxruntime/contrib_ops/cpu/transformers/sequences.h b/onnxruntime/contrib_ops/cpu/transformers/sequences.h index 7dd1f28d270c7..e2f6b29a77a2c 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/sequences.h +++ b/onnxruntime/contrib_ops/cpu/transformers/sequences.h @@ -5,6 +5,7 @@ #include #include "contrib_ops/cpu/transformers/generation_shared.h" +#include "contrib_ops/cpu/utils/console_dumper.h" namespace onnxruntime { namespace contrib { diff --git a/onnxruntime/contrib_ops/cpu/transformers/subgraph_base.cc b/onnxruntime/contrib_ops/cpu/transformers/subgraph_base.cc index 7757435990a65..537d066b264a1 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/subgraph_base.cc +++ b/onnxruntime/contrib_ops/cpu/transformers/subgraph_base.cc @@ -36,12 +36,9 @@ Subgraph::Subgraph( auto& subgraph_inputs = subgraph.GetInputs(); auto& subgraph_outputs = subgraph.GetOutputs(); - // inputs: input_ids, position_ids, attention_mask, past_0, past_1, ... - // outputs: logits, present_0, present_1, ... num_subgraph_inputs = static_cast(subgraph_inputs.size()); num_subgraph_outputs = static_cast(subgraph_outputs.size()); - // CheckSubgraph will verify inputs and outputs later. subgraph_input_names.reserve(num_subgraph_inputs); for (int i = 0; i < num_subgraph_inputs; ++i) { subgraph_input_names.push_back(subgraph_inputs[i]->Name()); @@ -68,10 +65,9 @@ Status Subgraph::Setup(const SessionState& session_state, InlinedVector feed_names; feed_names.reserve(static_cast(num_subgraph_inputs) + static_cast(num_implicit_inputs)); - // Use the first output (logits) to find device location. + // Use the first output to find device location. const OrtDevice& default_location = utils::FindDeviceForValue(subgraph_session_state, subgraph_output_names[0]); - // The position_ids, attention_mask, past_0, ... are created by this operator so the name doesn't matter. feed_names.insert(feed_names.end(), subgraph_input_names.begin(), subgraph_input_names.end()); const auto& subgraph_map = subgraph_session_state.GetOrtValueNameIdxMap(); @@ -174,13 +170,15 @@ Status Subgraph::GetParameters(const ONNX_NAMESPACE::TensorShapeProto* past_shap } // Logits shape is like (batch_size, seq_len, vocabulary_size) - ORT_RETURN_IF(logits_shape->dim_size() != 3, - "subgraph logits output is expected to have 3 dimension, got ", logits_shape->dim_size()); + if (logits_shape != nullptr) { + ORT_RETURN_IF(logits_shape->dim_size() != 3, + "subgraph logits output is expected to have 3 dimension, got ", logits_shape->dim_size()); - ORT_RETURN_IF(!logits_shape->dim(2).has_dim_value() || logits_shape->dim(2).dim_value() <= 0, - "subgraph past state dimension 2 shall have a positive value for vocabulary size"); + ORT_RETURN_IF(!logits_shape->dim(2).has_dim_value() || logits_shape->dim(2).dim_value() <= 0, + "subgraph past state dimension 2 shall have a positive value for vocabulary size"); - this->vocab_size = static_cast(logits_shape->dim(2).dim_value()); + this->vocab_size = static_cast(logits_shape->dim(2).dim_value()); + } return Status::OK(); } diff --git a/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_decoder.cc b/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_decoder.cc index 997beb198f450..09bce9828aa33 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_decoder.cc +++ b/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_decoder.cc @@ -6,11 +6,12 @@ #include "core/framework/tensorprotoutils.h" #include "core/framework/utils.h" #include "core/providers/cpu/tensor/utils.h" -#include #include "contrib_ops/cpu/transformers/subgraph_t5_decoder.h" #include "contrib_ops/cpu/utils/dump_tensor.h" #include "contrib_ops/cpu/transformers/generation_device_helper.h" #include "contrib_ops/cpu/transformers/sequences.h" +#include +#include namespace onnxruntime { namespace contrib { @@ -20,9 +21,9 @@ namespace transformers { Inputs: input_ids: int32 (B, 1) - encoder_input_ids: int32 (B, encode_sequence_length) (optional) + encoder_input_ids: int32 (B, encode_sequence_length) (optional for old format; removed in new format) encoder_attention_mask: int32 (B, encode_sequence_length) - encoder_hidden_states: (B, encode_sequence_length, encoder_hidden_size) (optional) + encoder_hidden_states: (B, encode_sequence_length, encoder_hidden_size) (optional for old format; removed in new format) past_key_self_0: (B, num_heads, past_decode_sequence_length, head_size) past_value_self_0: (B, num_heads, past_decode_sequence_length, head_size) @@ -141,14 +142,23 @@ Status T5DecoderSubgraph::Validate(const std::vector& subgraph_i } // Create inputs for decoder from the following data sources: -// encoder feeds: encoder_input_ids, encoder_attention_mask, decoder_input_ids (with start tokens) -// encoder fetches: logits, -// encoder_hidden_states, -// present_key_self_0, present_value_self_0, ..., present_key_cross_0, present_value_cross_0, ... -// decoder_feeds: input_ids, -// encoder_attention_mask, -// encoder_hidden_states, -// present_key_self_0, present_value_self_0, ..., present_key_cross_0, present_value_cross_0, ... +// New format: +// encoder feeds: encoder_input_ids, encoder_attention_mask +// encoder fetches: present_key_cross_0, present_value_cross_0, ... +// decoder_feeds: input_ids, encoder_attention_mask, +// present_key_self_0, present_value_self_0, ..., +// present_key_cross_0, present_value_cross_0, ... +// past_seq_len (optional), num_beams (optional), cache_indirection (optional) +// +// Old format: +// encoder feeds: encoder_input_ids, encoder_attention_mask, decoder_input_ids (with start tokens) +// encoder fetches: logits, encoder_hidden_states, +// present_key_self_0, present_value_self_0, ..., +// present_key_cross_0, present_value_cross_0, ... +// decoder_feeds: input_ids, encoder_input_ids (optional), encoder_attention_mask, encoder_hidden_states (optional), +// present_key_self_0, present_value_self_0, ..., +// present_key_cross_0, present_value_cross_0, ... +// past_seq_len (optional), num_beams (optional), cache_indirection (optional) Status T5DecoderSubgraph::CreateInitialFeeds( AllocatorPtr cpu_allocator, gsl::span beam_next_tokens, @@ -162,8 +172,7 @@ Status T5DecoderSubgraph::CreateInitialFeeds( const GenerationDeviceHelper::ExpandBufferFunc& expand_buffer_float16_func, int num_beam, Stream* stream, - bool use_sequence_as_input_ids, - int cur_len, + bool copy_sequence_to_input_ids, transformers::Sequences& sequences, int past_present_share_buffer_max_seq_len, bool need_cache_indir, @@ -173,34 +182,30 @@ Status T5DecoderSubgraph::CreateInitialFeeds( // Allocate subgraph inputs from same device as inputs of encoder subgraph. AllocatorPtr allocator = session_state_->GetAllocator(encoder_feeds[0].Get().Location()); + int batch_beam_size = static_cast(encoder_fetches[0].Get().Shape()[0]) * num_beam; + // Copy beam next tokens in CPU to input_ids in provider device (CPU for CPU EP, or GPU for CUDA EP). - int batch_beam_size = static_cast(beam_next_tokens.size()); - int sequence_length = !use_sequence_as_input_ids ? 1 : cur_len; + int sequence_length = !copy_sequence_to_input_ids ? 1 : sequences.GetSequenceLength(); int64_t dims[] = {batch_beam_size, sequence_length}; TensorShape input_ids_shape(&dims[0], 2); OrtValue input_ids; Tensor::InitOrtValue(DataTypeImpl::GetType(), input_ids_shape, allocator, input_ids); - int32_t* input_ids_data = input_ids.GetMutable()->MutableData(); - AllocatorPtr buffer_allocator = std::make_shared(); - size_t total_size = static_cast(cur_len) * static_cast(batch_beam_size); - size_t total_size_bytes = total_size * sizeof(int); - auto seq_copy = IAllocator::MakeUniquePtr(buffer_allocator, total_size_bytes, false, stream); - int* seq_copy_ptr = seq_copy.get(); - - if (!use_sequence_as_input_ids_) { + + // Prepare data for input_ids. + if (!copy_sequence_to_input_ids) { // use next tokens for input_ids. ORT_RETURN_IF_ERROR(device_copy_int32_func( input_ids.GetMutable()->MutableDataAsSpan(), beam_next_tokens, stream, DeviceCopyDirection::hostToDevice)); - } else { + } else { // use whole sequences for input_ids. + int32_t* input_ids_data = input_ids.GetMutable()->MutableData(); if (use_cuda) { auto sequences_buffer = sequences.GetCurrentDeviceSequences(); for (int i = 0; i < batch_beam_size; i++) { - size_t batch_beam_stride = static_cast(i) * static_cast(sequences.GetMaxLength()); - int seq_size = sequences.GetSequenceLength(); - gsl::span sequence = sequences_buffer.subspan(batch_beam_stride, seq_size); - gsl::span temp_input(input_ids_data + static_cast(i) * seq_size, seq_size); + size_t offset = static_cast(i) * static_cast(sequences.GetMaxLength()); + gsl::span sequence = sequences_buffer.subspan(offset, sequence_length); + gsl::span temp_input(input_ids_data + static_cast(i) * sequence_length, sequence_length); ORT_RETURN_IF_ERROR(device_copy_int32_func( temp_input, sequence, @@ -208,12 +213,19 @@ Status T5DecoderSubgraph::CreateInitialFeeds( DeviceCopyDirection::deviceToDevice)); } } else { - const size_t cur_len_bytes = cur_len * sizeof(int); + size_t total_size = static_cast(sequence_length) * static_cast(batch_beam_size); + size_t total_size_bytes = total_size * sizeof(int); + AllocatorPtr buffer_allocator = std::make_shared(); + // TODO: not need extra buffer. Copy directly to input_ids_data instead like the user_cuda above. + auto seq_copy = IAllocator::MakeUniquePtr(buffer_allocator, total_size_bytes, false, stream); + int* seq_copy_ptr = seq_copy.get(); + + const size_t sequence_bytes = sequence_length * sizeof(int); for (int i = 0; i < batch_beam_size; i++) { gsl::span sequence = sequences.GetSequence(i); const int32_t* sequence_data = sequence.data(); - ptrdiff_t seq_index = static_cast(i) * cur_len; - memcpy(seq_copy_ptr + seq_index, sequence_data, cur_len_bytes); + ptrdiff_t seq_index = static_cast(i) * sequence_length; + memcpy(seq_copy_ptr + seq_index, sequence_data, sequence_bytes); } gsl::span temp_input(input_ids_data, total_size); gsl::span temp_sequence(seq_copy_ptr, total_size); @@ -227,9 +239,11 @@ Status T5DecoderSubgraph::CreateInitialFeeds( // The ordering is the same as used in Setup. decoder_feeds.reserve(static_cast(num_subgraph_inputs) + static_cast(num_implicit_inputs)); + + // input 0: input_ids decoder_feeds.push_back(input_ids); - if (has_encoder_input_ids_) { + if (has_encoder_input_ids_) { // encoder_input_ids is optional // The encoder_input_ids is copied from the first input of encoder. OrtValue expanded_encoder_input_ids; ORT_RETURN_IF_ERROR(expand_buffer_int32_func(stream, @@ -251,70 +265,66 @@ Status T5DecoderSubgraph::CreateInitialFeeds( expanded_decoder_attention_masks, false, 0 /*max_sequence_length*/)); - decoder_feeds.push_back(expanded_decoder_attention_masks); if (!past_present_share_buffer_) { past_present_share_buffer_max_seq_len = 0; } - // When first_past_input_index_ == 3, the encoder_hidden_states and past states are copied from the second output - // of encoder. - // When first_past_input_index_ == 2, the past states are copied from the second output of encoder. - // TODO - probably more robust to introduce a encoder_out/decoder_in mapping instead of relying on positions. - // What happens if encoder_hidden_states is present in the encoder_fetches but not in the decoder_feeds? - for (size_t j = static_cast(2) - has_hidden_state_; j < encoder_fetches.size(); j++) { - if (j == 1) { - ORT_RETURN_IF(has_hidden_state_ == false, "Invalid hidden_states expension: has_hidden_state_ == false"); - OrtValue expanded_hidden_states; - if (is_output_float16_) { - ORT_RETURN_IF_ERROR(expand_buffer_float16_func(stream, - encoder_fetches[j], - num_beam, - allocator, - expanded_hidden_states, - false, - 0 /*max_sequence_length*/)); - } else { - ORT_RETURN_IF_ERROR(expand_buffer_float_func(stream, - encoder_fetches[j], - num_beam, - allocator, - expanded_hidden_states, - false, - 0 /*max_sequence_length*/)); - } - decoder_feeds.push_back(expanded_hidden_states); - } else { +// macro to expand encoder outputs and append to decoder feeds. +#define ADD_DECODER_FEED(encoder_output, is_dynamic_kv_cache) \ + OrtValue expanded; \ + if (is_output_float16_) { \ + ORT_RETURN_IF_ERROR(expand_buffer_float16_func(stream, encoder_output, num_beam, allocator, expanded, false, \ + is_dynamic_kv_cache ? past_present_share_buffer_max_seq_len : 0)); \ + } else { \ + ORT_RETURN_IF_ERROR(expand_buffer_float_func(stream, encoder_output, num_beam, allocator, expanded, false, \ + is_dynamic_kv_cache ? past_present_share_buffer_max_seq_len : 0)); \ + } \ + decoder_feeds.push_back(expanded); + + // The encoder_hidden_states is copied from the second output of encoder. + if (has_hidden_state_) { + ADD_DECODER_FEED(encoder_fetches[1], false); + } + + // New format of encoder has only cross outputs. + bool is_new_format = (static_cast(encoder_fetches.size()) == 2 * num_layers); + if (is_new_format) { + for (int i = 0; i < 2 * num_layers; i++) { + // cross shape is (batch_size, num_heads, encode_sequence_length, head_size) + const TensorShape& cross_shape = encoder_fetches[0].Get().Shape(); + ORT_ENFORCE(cross_shape.NumDimensions() == 4); + + // Shape for kv cache: (batch_size * num_beam, num_heads, max_seq_len, head_size) + int64_t cache_dims[4] = {0}; + cross_shape.CopyDims(cache_dims, cross_shape.NumDimensions()); + cache_dims[0] *= num_beam; + cache_dims[2] = past_present_share_buffer_max_seq_len; + TensorShape expanded_shape(&cache_dims[0], cross_shape.NumDimensions()); + + MLDataType element_type = encoder_fetches[0].Get().DataType(); + OrtValue past; + Tensor::InitOrtValue(element_type, expanded_shape, allocator, past); + decoder_feeds.push_back(past); + } + + // Add cross inputs from encoder output. + for (size_t j = 0; j < encoder_fetches.size(); j++) { + ADD_DECODER_FEED(encoder_fetches[j], false); + } + } else { + // present_* output of encoder are added as decoder inputs. + for (size_t j = 2; j < encoder_fetches.size(); j++) { // past key/value for cross attention does not need to be initialized with max_seq_len since they are static. - bool use_max_seq_len = (j - first_past_input_index_) < 2 * static_cast(num_layers); - - OrtValue expanded_cache; - if (is_output_float16_) { - ORT_RETURN_IF_ERROR(expand_buffer_float16_func(stream, - encoder_fetches[j], - num_beam, - allocator, - expanded_cache, - false, - use_max_seq_len ? past_present_share_buffer_max_seq_len : 0)); - } else { - ORT_RETURN_IF_ERROR(expand_buffer_float_func(stream, - encoder_fetches[j], - num_beam, - allocator, - expanded_cache, - false, - use_max_seq_len ? past_present_share_buffer_max_seq_len : 0)); - } - decoder_feeds.push_back(expanded_cache); + bool is_dynamic_kv_cache = (j - first_past_input_index_) < 2 * static_cast(num_layers); + ADD_DECODER_FEED(encoder_fetches[j], is_dynamic_kv_cache); } } - // TODO: This part shares the similar logic with CreateInitialFeeds() in subgraph_gpt.cc. We should refactor it. if (past_present_share_buffer_) { - // Past sequence length feed - ORT_RETURN_IF_ERROR(AppendPastSequenceLength(decoder_feeds, cpu_allocator, 1)); + // Past sequence length set to 0 + ORT_RETURN_IF_ERROR(AppendPastSequenceLength(decoder_feeds, cpu_allocator, is_new_format ? 0 : 1)); // Add beam search specific inputs if (need_cache_indir) { const int64_t batch_size = static_cast(batch_beam_size / num_beam); diff --git a/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_decoder.h b/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_decoder.h index b5d727b67924c..87782d47cdbe1 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_decoder.h +++ b/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_decoder.h @@ -45,7 +45,6 @@ class T5DecoderSubgraph : public Subgraph { int num_beam, Stream* stream, bool use_sequence_as_input_ids, - int cur_len, transformers::Sequences& sequences, int past_present_share_buffer_max_seq_len = -1, bool need_cache_indir = false, @@ -72,6 +71,10 @@ class T5DecoderSubgraph : public Subgraph { return use_sequence_as_input_ids_; } + inline bool UseEncoderHiddenState() const { + return has_hidden_state_; + } + protected: int first_past_input_index_; int first_present_output_index_; diff --git a/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_encoder.cc b/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_encoder.cc index d59db4afac2c2..a54c0d960980c 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_encoder.cc +++ b/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_encoder.cc @@ -15,70 +15,97 @@ namespace transformers { /* T5 Encoder Subgraph (It also contains decoder initialization where decoder_input_ids are filled with start token ID). - Inputs: + New format: + Inputs: encoder_input_ids: int32 (B, encode_sequence_length) encoder_attention_mask: int32 (B, encode_sequence_length) - decoder_input_ids: int32 (B, 1) Outputs: - logits: (B, 1, vocab_size) - encoder_hidden_states: (B, encode_sequence_length, encoder_hidden_size) - - present_key_self_0: (B, num_heads, 1, head_size) - present_value_self_0: (B, num_heads, 1, head_size) - ... (for each self attention layer) - present_key_cross_0: (B, num_heads, encode_sequence_length, head_size) present_value_cross_0: (B, num_heads, encode_sequence_length, head_size) ... (for each cross attention layer) - Note: - Here, B = batch_size * num_beams since we expand the inputs. - Ideally, we could use B=batch_size and expand the outputs with a factor of num_beams. - Data type of input or output is float or float16 if not specified. + Old format: + Inputs: + encoder_input_ids: int32 (B, encode_sequence_length) + encoder_attention_mask: int32 (B, encode_sequence_length) + decoder_input_ids: int32 (B, 1) + + Outputs: + logits: (B, 1, vocab_size) + encoder_hidden_states: (B, encode_sequence_length, encoder_hidden_size) + + present_key_self_0: (B, num_heads, 1, head_size) + present_value_self_0: (B, num_heads, 1, head_size) + ... (for each self attention layer) + + present_key_cross_0: (B, num_heads, encode_sequence_length, head_size) + present_value_cross_0: (B, num_heads, encode_sequence_length, head_size) + ... (for each cross attention layer) + + Note: + Here, B = batch_size * num_beams since we expand the inputs. + Ideally, we could use B=batch_size and expand the outputs with a factor of num_beams. + Data type of input or output is float or float16 if not specified. */ Status T5EncoderSubgraph::Validate(const std::vector& subgraph_inputs, const std::vector& subgraph_outputs) { - ORT_RETURN_IF(num_subgraph_inputs != 3, "expect 3 inputs, got:", num_subgraph_inputs); - - ORT_RETURN_IF(num_subgraph_outputs < 6, "expect >=6 outputs, got:", num_subgraph_outputs); - ORT_RETURN_IF((static_cast(subgraph_outputs.size()) - first_present_output_index_) % 4 != 0, - "number of outputs expected to be 2 + 4 * layers, got:", num_subgraph_outputs); + constexpr auto int32_type = ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_INT32; + constexpr auto float32_type = ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_FLOAT; + constexpr auto float16_type = ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_FLOAT16; + ORT_RETURN_IF(num_subgraph_inputs != 2 && num_subgraph_inputs != 3, "expect 2 or 3 inputs, got:", num_subgraph_inputs); ORT_RETURN_IF(subgraph_inputs[0]->Name() != "encoder_input_ids", "encoder subgraph input 0 shall be named as encoder_input_ids, got: ", subgraph_inputs[0]->Name()); ORT_RETURN_IF(subgraph_inputs[1]->Name() != "encoder_attention_mask", "encoder subgraph input 1 shall be named as encoder_attention_mask, got: ", subgraph_inputs[1]->Name()); - ORT_RETURN_IF(subgraph_inputs[2]->Name() != "decoder_input_ids", - "encoder subgraph input 2 shall be named as decoder_input_ids, got: ", subgraph_inputs[2]->Name()); - - ORT_RETURN_IF(subgraph_outputs[0]->Name() != "logits", - "encoder subgraph output 0 shall be named as logits, got: ", subgraph_outputs[0]->Name()); - ORT_RETURN_IF(subgraph_outputs[1]->Name() != "encoder_hidden_states", - "encoder subgraph output 1 shall be named encoder_hidden_states, got: ", subgraph_outputs[1]->Name()); - ORT_RETURN_IF(subgraph_outputs[2]->Name() != "present_key_self_0", - "encoder subgraph output 2 shall be named as present_key_self_0, got: ", subgraph_outputs[2]->Name()); - ORT_RETURN_IF(subgraph_outputs[3]->Name() != "present_value_self_0", - "encoder subgraph output 3 shall be named as present_value_self_0, got: ", subgraph_outputs[3]->Name()); - - const ONNX_NAMESPACE::TensorShapeProto* past_shape = subgraph_outputs[2]->Shape(); - const ONNX_NAMESPACE::TensorShapeProto* logits_shape = subgraph_outputs[0]->Shape(); - - // Save parameters related to the subgraph. - ORT_RETURN_IF_ERROR(GetParameters(past_shape, logits_shape, false)); - num_layers = (static_cast(subgraph_outputs.size()) - first_present_output_index_) / 4; - - constexpr auto int32_type = ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_INT32; - constexpr auto float32_type = ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_FLOAT; - constexpr auto float16_type = ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_FLOAT16; ORT_RETURN_IF(subgraph_inputs[0]->TypeAsProto()->tensor_type().elem_type() != int32_type, "encoder subgraph input 0 (encoder_input_ids) shall have int32 type"); ORT_RETURN_IF(subgraph_inputs[1]->TypeAsProto()->tensor_type().elem_type() != int32_type, "encoder subgraph input 1 (encoder_attention_mask) shall have int32 type"); - ORT_RETURN_IF(subgraph_inputs[2]->TypeAsProto()->tensor_type().elem_type() != int32_type, - "encoder subgraph input 2 (decoder_input_ids) shall have int32 type"); + + if (num_subgraph_inputs == 2) { + ORT_RETURN_IF(num_subgraph_outputs < 2 || num_subgraph_outputs % 2 != 0, + "number of outputs expected to be 2 * layers, got:", num_subgraph_outputs); + + ORT_RETURN_IF(subgraph_outputs[0]->Name() != "present_key_cross_0", + "encoder subgraph output 0 shall be named as present_key_cross_0, got: ", subgraph_outputs[0]->Name()); + ORT_RETURN_IF(subgraph_outputs[1]->Name() != "present_value_cross_0", + "encoder subgraph output 1 shall be named as present_value_cross_0, got: ", subgraph_outputs[1]->Name()); + + // Deduce num_heads and head_size parameters from shape of graph outputs + const ONNX_NAMESPACE::TensorShapeProto* past_shape = subgraph_outputs[0]->Shape(); + const ONNX_NAMESPACE::TensorShapeProto* logits_shape = nullptr; + ORT_RETURN_IF_ERROR(GetParameters(past_shape, logits_shape, false)); + + num_layers = num_subgraph_outputs / 2; + } else { + ORT_RETURN_IF(num_subgraph_outputs < 6 || (num_subgraph_outputs - first_present_output_index_) % 4 != 0, + "number of outputs expected to be 2 + 4 * layers, got:", num_subgraph_outputs); + + ORT_RETURN_IF(subgraph_inputs[2]->Name() != "decoder_input_ids", + "encoder subgraph input 2 shall be named as decoder_input_ids, got: ", subgraph_inputs[2]->Name()); + ORT_RETURN_IF(subgraph_inputs[2]->TypeAsProto()->tensor_type().elem_type() != int32_type, + "encoder subgraph input 2 (decoder_input_ids) shall have int32 type"); + + ORT_RETURN_IF(subgraph_outputs[0]->Name() != "logits", + "encoder subgraph output 0 shall be named as logits, got: ", subgraph_outputs[0]->Name()); + ORT_RETURN_IF(subgraph_outputs[1]->Name() != "encoder_hidden_states", + "encoder subgraph output 1 shall be named encoder_hidden_states, got: ", subgraph_outputs[1]->Name()); + ORT_RETURN_IF(subgraph_outputs[2]->Name() != "present_key_self_0", + "encoder subgraph output 2 shall be named as present_key_self_0, got: ", subgraph_outputs[2]->Name()); + ORT_RETURN_IF(subgraph_outputs[3]->Name() != "present_value_self_0", + "encoder subgraph output 3 shall be named as present_value_self_0, got: ", subgraph_outputs[3]->Name()); + + // Deduce num_heads, head_size and vocab_size from shape of graph outputs + const ONNX_NAMESPACE::TensorShapeProto* past_shape = subgraph_outputs[2]->Shape(); + const ONNX_NAMESPACE::TensorShapeProto* logits_shape = subgraph_outputs[0]->Shape(); + ORT_RETURN_IF_ERROR(GetParameters(past_shape, logits_shape, false)); + + num_layers = (num_subgraph_outputs - first_present_output_index_) / 4; + } auto output_type = subgraph_outputs[0]->TypeAsProto()->tensor_type().elem_type(); ORT_RETURN_IF(output_type != float32_type && output_type != float16_type, @@ -86,7 +113,7 @@ Status T5EncoderSubgraph::Validate(const std::vector& subgraph_i for (int i = 1; i < num_subgraph_outputs; i++) { ORT_RETURN_IF(subgraph_outputs[i]->TypeAsProto()->tensor_type().elem_type() != output_type, - "encoder subgraph outputs 1, 2, ... shall have same data type"); + "encoder subgraph outputs shall have same data type"); } is_output_float16_ = (output_type == float16_type); @@ -120,7 +147,6 @@ Status T5EncoderSubgraph::CreateInitialFeeds( } ORT_RETURN_IF(cpu_allocator == nullptr, "cpu_allocator shouldn't be nullptr"); - // TODO(tianleiwu): expand the outputs instead of inputs to save computation. OrtValue encoder_input_ids; OrtValue encoder_attention_mask; ORT_RETURN_IF_ERROR(create_encoder_inputs_func(&original_encoder_input_ids, @@ -136,9 +162,10 @@ Status T5EncoderSubgraph::CreateInitialFeeds( AllocatorPtr default_allocator = session_state_->GetAllocator(provider->GetOrtDeviceByMemType(OrtMemTypeDefault)); AllocatorPtr pinned_allocator = session_state_->GetAllocator(provider->GetOrtDeviceByMemType(OrtMemTypeCPU)); const OrtMemoryInfo& location = default_allocator->Info(); + ORT_RETURN_IF_ERROR(add_to_feeds_func( ort_stream, - {encoder_input_ids, encoder_attention_mask, decoder_input_ids}, + num_subgraph_inputs == 2 ? std::initializer_list{encoder_input_ids, encoder_attention_mask} : std::initializer_list{encoder_input_ids, encoder_attention_mask, decoder_input_ids}, feeds, buffer, default_allocator, diff --git a/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_encoder.h b/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_encoder.h index a79f677f5a043..33fd522bdfd82 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_encoder.h +++ b/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_encoder.h @@ -16,7 +16,11 @@ class T5EncoderSubgraph : public Subgraph { const onnxruntime::Node& node_in, const std::string& attribute_name, const GraphViewer& subgraph_in) : Subgraph(node_in, attribute_name, subgraph_in) { - first_present_output_index_ = 2; + has_logits_output_ = num_subgraph_outputs > 0 && subgraph_output_names[0] == "logits"; + + // Old format: The first output is logits, the second one is encoder_hidden_states. + // New format: No logits and encoder_hidden_states. All outputs are cross. + first_present_output_index_ = HasLogitsOutput() ? 2 : 0; } // Create inputs for first inference of subgraph. @@ -36,11 +40,18 @@ class T5EncoderSubgraph : public Subgraph { Status Validate(const std::vector& subgraph_inputs, const std::vector& subgraph_outputs) override; +#ifdef DEBUG_GENERATION int GetFirstPresentOutputIndex() const { return first_present_output_index_; } +#endif + + bool HasLogitsOutput() const { + return has_logits_output_; + } protected: + bool has_logits_output_; int first_present_output_index_; }; diff --git a/onnxruntime/contrib_ops/cpu/utils/debug_macros.h b/onnxruntime/contrib_ops/cpu/utils/debug_macros.h index d5cbaa0a3e6b7..47d0fc5e4008c 100644 --- a/onnxruntime/contrib_ops/cpu/utils/debug_macros.h +++ b/onnxruntime/contrib_ops/cpu/utils/debug_macros.h @@ -15,11 +15,13 @@ #if DUMP_CPU_TENSOR_LEVEL > 0 #define DUMP_CPU_TENSOR_INIT() onnxruntime::contrib::CpuTensorConsoleDumper cpu_dumper #define DUMP_CPU_TENSOR(...) cpu_dumper.Print(__VA_ARGS__) -#define DUMP_STRING(...) cpu_dumper.Print(::onnxruntime::MakeString(__VA_ARGS__)) +#define DUMP_CPU_STRING_INIT() DUMP_CPU_TENSOR_INIT() +#define DUMP_CPU_STRING(...) cpu_dumper.Print(::onnxruntime::MakeString(__VA_ARGS__)) #else -#define DUMP_CPU_TENSOR_INIT() +#define DUMP_CPU_TENSOR_INIT(...) #define DUMP_CPU_TENSOR(...) -#define DUMP_STRING(...) +#define DUMP_CPU_STRING_INIT(...) +#define DUMP_CPU_STRING(...) #endif #if DUMP_CPU_TENSOR_LEVEL > 1 @@ -32,9 +34,13 @@ #if DUMP_TENSOR_LEVEL > 0 #define DUMP_TENSOR_INIT() onnxruntime::contrib::cuda::CudaTensorConsoleDumper dumper #define DUMP_TENSOR(...) dumper.Print(__VA_ARGS__) +#define DUMP_STRING_INIT() DUMP_TENSOR_INIT() +#define DUMP_STRING(...) dumper.Print(::onnxruntime::MakeString(__VA_ARGS__)) #else -#define DUMP_TENSOR_INIT() +#define DUMP_TENSOR_INIT(...) #define DUMP_TENSOR(...) +#define DUMP_STRING_INIT(...) +#define DUMP_STRING(...) #endif #if DUMP_TENSOR_LEVEL > 1 diff --git a/onnxruntime/contrib_ops/cuda/bert/attention_data.h b/onnxruntime/contrib_ops/cuda/bert/attention_data.h new file mode 100644 index 0000000000000..c7b06d50858b4 --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/attention_data.h @@ -0,0 +1,185 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include "contrib_ops/cpu/bert/attention_common.h" +#include "contrib_ops/cpu/bert/attention_parameters.h" + +namespace onnxruntime { +namespace contrib { +namespace cuda { + +template +struct AttentionData { + T* gemm_buffer = nullptr; + const T* bias = nullptr; + int* seqlens_k_total = nullptr; + + const T* query = nullptr; + const T* key = nullptr; + const T* value = nullptr; + const int* mask_index = nullptr; + gsl::span mask_index_dims; + const T* past = nullptr; + const T* past_key = nullptr; + const T* past_value = nullptr; + const int32_t* cache_indirection = nullptr; + const T* attention_bias = nullptr; + + bool has_qkv_workspace = false; + T* workspace = nullptr; + + T* output = nullptr; + T* present = nullptr; + T* present_key = nullptr; + T* present_value = nullptr; + void* output_qk = nullptr; + + void* fused_runner = nullptr; + const void* fused_cross_attention_kernel = nullptr; + + bool use_flash_attention = false; + bool use_memory_efficient_attention = false; + bool use_decoder_masked_multihead_attention = false; + + const int32_t* cumulated_sequence_length_q_cache = nullptr; + const int32_t* cumulated_sequence_length_kv_cache = nullptr; + + // Intermediate data + T* q = nullptr; + T* k = nullptr; + T* v = nullptr; + T* scratch = nullptr; + AttentionQkvFormat qkv_format = AttentionQkvFormat::UNKNOWN; + + // Flash buffers + T* softmax_lse = nullptr; + T* softmax_lse_accum = nullptr; + T* out_accum = nullptr; + + // Flash Atttention and Lean Attention + int num_splits; + + // Lean Attention + bool use_lean_attention = false; +#if USE_LEAN_ATTENTION + int grid_dim_z = 0; + int max_tiles_per_tb = 0; + int high_load_tbs = 0; + int tiles_per_head = 0; + int* lean_sync_flag = nullptr; +#endif + + // For Debugging + size_t workspace_bytes = 0; + bool allow_debug_info = false; + + // For MultiHeadAttention only. + AttentionKernelType kernel_type = AttentionKernelType::AttentionKernel_Default; + AllocatorPtr allocator = nullptr; + bool IsUnfused() const { + return kernel_type == AttentionKernelType::AttentionKernel_Unfused; + } + + // For DecoderMaskedMultiHeadAttention + T* q_bias = nullptr; + T* k_bias = nullptr; + T* v_bias = nullptr; + + void PrintDebugInfo() const { + std::cout << "flash=" << use_flash_attention + << ", lean=" << use_lean_attention + << ", efficient=" << use_memory_efficient_attention + << ", fused_runner=" << (fused_runner != nullptr) + << ", fused_cross=" << (fused_cross_attention_kernel != nullptr) + << ", bias=" << (bias != nullptr) + << ", attn_bias=" << (attention_bias != nullptr) + << ", mask_dims=" << mask_index_dims.size() + << ", has_qkv_workspace=" << has_qkv_workspace + << ", workspace=" << workspace_bytes + << ", past=" << (past != nullptr ? 1 : (past_key != nullptr ? 2 : 0)) + << ", present=" << (present != nullptr ? 1 : (present_key != nullptr ? 2 : 0)) + << std::endl; + } +}; + +template +struct PackedAttentionData { + T* gemm_buffer; + const T* bias; + const T* attention_bias; + const int32_t* token_offset; + const int32_t* cumulative_sequence_length; + + T* workspace; + T* output; + + void* fused_runner; + + bool use_memory_efficient_attention; +}; + +template +struct PackedMultiHeadAttentionData { + const T* query; + const T* key; + const T* value; + const T* bias; + const T* attention_bias; + + const int32_t* token_offset; + const int32_t* cumulative_sequence_length; + + AttentionQkvFormat source_qkv_format; + + bool no_qkv_workspace; + T* workspace; + T* output; + + void* fused_runner; + + bool use_flash_attention; + bool use_memory_efficient_attention; +}; + +template +struct GroupQueryAttentionData { + // Input Tensors + const T* query = nullptr; + const T* key = nullptr; + const T* value = nullptr; + const T* past_key = nullptr; + const T* past_value = nullptr; + int* seqlens_k = nullptr; + const T* cos_cache = nullptr; + const T* sin_cache = nullptr; + + // Flash buffers + T* softmax_lse = nullptr; + T* softmax_lse_accum = nullptr; + T* out_accum = nullptr; + int* seqlens_k_buff = nullptr; + + // Memory Efficient buffers + T* fmha_buffer = nullptr; + T* unpacked_qkv_buffer = nullptr; + T* rotary_buffer = nullptr; + T* k = nullptr; + T* v = nullptr; + + // Output Tensors + T* output = nullptr; + T* present_key = nullptr; + T* present_value = nullptr; + + // Kernel Flags + bool use_flash_attention = false; + bool use_memory_efficient_attention = false; +}; + +} // namespace cuda +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/attention_impl.cu b/onnxruntime/contrib_ops/cuda/bert/attention_impl.cu index 9e017544d7cff..51311715d3b2a 100644 --- a/onnxruntime/contrib_ops/cuda/bert/attention_impl.cu +++ b/onnxruntime/contrib_ops/cuda/bert/attention_impl.cu @@ -29,18 +29,23 @@ limitations under the License. #include "core/providers/cuda/cu_inc/common.cuh" #include "core/providers/cuda/cuda_common.h" #include "core/providers/cuda/shared_inc/fpgeneric.h" -#include "contrib_ops/cuda/bert/attention_softmax.h" -#include "contrib_ops/cuda/bert/transformer_common.h" -#include "contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/mha_runner.h" -#include "contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/cross_attention/fmha_cross_attention.h" +#include "core/platform/env_var_utils.h" #include "contrib_ops/cpu/bert/attention_base.h" +#include "contrib_ops/cpu/bert/attention_common.h" +#include "contrib_ops/cpu/bert/attention_parameters.h" +#include "contrib_ops/cuda/bert/attention_impl.h" +#include "contrib_ops/cuda/bert/attention_kv_cache.h" +#include "contrib_ops/cuda/bert/attention_qk.h" +#include "contrib_ops/cuda/bert/attention_softmax.h" #include "contrib_ops/cuda/bert/bert_padding.h" -#include "contrib_ops/cuda/utils/dump_cuda_tensor.h" #include "contrib_ops/cuda/bert/cutlass_fmha/memory_efficient_attention.h" #include "contrib_ops/cuda/bert/cudnn_fmha/cudnn_flash_attention.h" #include "contrib_ops/cuda/bert/flash_attention/flash_api.h" #include "contrib_ops/cuda/bert/lean_attention/lean_api.h" -#include "contrib_ops/cuda/bert/attention_impl.h" +#include "contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/mha_runner.h" +#include "contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/cross_attention/fmha_cross_attention.h" +#include "contrib_ops/cuda/bert/transformer_common.h" +#include "contrib_ops/cuda/utils/dump_cuda_tensor.h" using namespace onnxruntime::cuda; using namespace onnxruntime::contrib::attention_softmax_cuda; @@ -507,7 +512,7 @@ Status EfficientAttention( p.seqstart_q_ptr = nullptr; p.seqstart_k_ptr = nullptr; } else { - p.seqlen_k_ptr = const_cast(reinterpret_cast(data.mask_index)); + p.seqlen_k_ptr = reinterpret_cast(data.mask_index); p.seqstart_q_ptr = p.seqlen_k_ptr + parameters.batch_size; p.seqstart_k_ptr = p.seqlen_k_ptr + 2 * parameters.batch_size + 1; } @@ -516,7 +521,7 @@ Status EfficientAttention( p.key = data.k; p.value = data.v; - p.attn_bias = (nullptr == data.attention_bias) ? nullptr : data.attention_bias; + p.attn_bias = data.attention_bias; p.broadcast_attn_bias_dim_0 = parameters.broadcast_attn_bias_dim_0; p.broadcast_attn_bias_dim_1 = parameters.broadcast_attn_bias_dim_1; @@ -533,7 +538,138 @@ Status EfficientAttention( } #endif -template +template +Status LaunchDecoderMaskedMultiHeadAttention( + const DecoderMaskedMultiHeadAttentionParameters& parameters, + cudaStream_t stream, + const int head_size) { + + DUMP_STRING_INIT(); + DUMP_STRING("DMMHA parameters..."); + DUMP_STRING("is_mha = ", (parameters.is_mha == true)); + DUMP_STRING("is_cross_attention = ", (parameters.is_cross_attention == true)); + DUMP_STRING("is_packed_qkv = ", (parameters.is_packed_qkv == true)); + DUMP_STRING("kv_data_in_flight = ", (parameters.kv_data_in_flight == true)); + + DUMP_STRING("Batch size = ", parameters.batch_size); + DUMP_STRING("Sequence length = ", parameters.sequence_length); + DUMP_STRING("Num heads = ", parameters.num_heads); + DUMP_STRING("Head size = ", parameters.head_size); + DUMP_STRING("Hidden size = ", parameters.hidden_size); + + DUMP_STRING("Past sequence length = ", parameters.past_sequence_length); + DUMP_STRING("KV sequence length = ", parameters.kv_sequence_length); + DUMP_STRING("Total sequence length = ", parameters.total_sequence_length); + DUMP_STRING("Max sequence length = ", parameters.max_sequence_length); + + DUMP_STRING("parameters.k is null = ", (parameters.k == nullptr)); + DUMP_STRING("parameters.v is null = ", (parameters.v == nullptr)); + DUMP_STRING("parameters.k_cache is null = ", (parameters.k_cache == nullptr)); + DUMP_STRING("parameters.v_cache is null = ", (parameters.v_cache == nullptr)); + + DUMP_STRING("parameters.q_bias is null = ", (parameters.q_bias == nullptr)); + DUMP_STRING("parameters.k_bias is null = ", (parameters.k_bias == nullptr)); + DUMP_STRING("parameters.v_bias is null = ", (parameters.v_bias == nullptr)); + + DUMP_STRING("parameters.attention_bias is null = ", (parameters.attention_bias == nullptr)); + DUMP_STRING("Scale = ", parameters.scale); + DUMP_STRING("Mask is null = ", (parameters.mask == nullptr)); + DUMP_STRING("Mask filter value = ", parameters.mask_filter_value); + + DUMP_STRING("Beam width = ", parameters.beam_width); + DUMP_STRING("parameters.cache_indir is null = ", (parameters.cache_indir == nullptr)); + DUMP_STRING("parameters.out_qk is null = ", (parameters.out_qk == nullptr)); + + switch (head_size) { + case 32: + mmha_launch_kernel(parameters, stream); + break; + + case 64: + mmha_launch_kernel(parameters, stream); + break; + + case 128: + mmha_launch_kernel(parameters, stream); + break; + + default: + return ORT_MAKE_STATUS(ONNXRUNTIME, NOT_IMPLEMENTED, + "Unsupported head size in DecoderMaskedMultiHeadAttention. Got head size: ", + head_size); + } + + return Status::OK(); +} + +template +Status DecoderMaskedMultiHeadAttention( + cudaStream_t stream, + contrib::AttentionParameters& parameters, + AttentionData& data, + float scale) { + assert(data.qkv_format == AttentionQkvFormat::Q_K_V_BSNH || + data.qkv_format == AttentionQkvFormat::Q_K_V_BSNH_BNSH_BNSH); + assert(parameters.mask_type == AttentionMaskType::MASK_NONE || + parameters.mask_type == AttentionMaskType::MASK_2D_KEY_PADDING); + assert(parameters.head_size == parameters.v_head_size); + + DecoderMaskedMultiHeadAttentionParameters p; + p.is_mha = true; + p.is_cross_attention = (data.past_key == nullptr && data.present_key == nullptr); + p.is_packed_qkv = false; + p.kv_data_in_flight = ParseEnvironmentVariableWithDefault(attention::kDecoderMaskedAttentionLoadKVDataInFlight, false); + + p.batch_size = parameters.batch_size; + p.sequence_length = parameters.sequence_length; + p.num_heads = parameters.num_heads; + p.head_size = parameters.head_size; + p.hidden_size = parameters.hidden_size; + + p.past_sequence_length = parameters.past_sequence_length; + p.kv_sequence_length = parameters.kv_sequence_length; + p.total_sequence_length = p.is_cross_attention ? parameters.kv_sequence_length : parameters.total_sequence_length; + p.max_sequence_length = p.is_cross_attention ? parameters.kv_sequence_length : parameters.max_sequence_length; + + p.q = data.q; + p.k = p.is_cross_attention ? nullptr : data.k; + p.v = p.is_cross_attention ? nullptr : data.v; + p.k_cache = p.is_cross_attention ? data.k : data.present_key; + p.v_cache = p.is_cross_attention ? data.v : data.present_value; + + p.q_bias = data.q_bias; + p.k_bias = data.k_bias; + p.v_bias = data.v_bias; + + p.attention_bias = const_cast(data.attention_bias); + p.broadcast_attn_bias_dim_0 = parameters.broadcast_attn_bias_dim_0; + p.broadcast_attn_bias_dim_1 = parameters.broadcast_attn_bias_dim_1; + + p.scale = scale; + p.mask = data.mask_index; + p.mask_filter_value = parameters.mask_filter_value; + + p.beam_width = parameters.beam_width; + p.cache_indir = data.cache_indirection; + + p.out = data.output; + p.out_qk = data.output_qk; + + // DecoderMaskedMultiHeadAttention(T, QK) is defined for: + // T = float, QK = float + // T = float, QK = half + // T = uint16_t, QK = float + // T = uint16_t, QK = half + if (std::is_same::value) { + return LaunchDecoderMaskedMultiHeadAttention(p, stream, parameters.head_size); + } + if (std::is_same::value) { + return LaunchDecoderMaskedMultiHeadAttention(p, stream, parameters.head_size); + } + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "DecoderMaskedMultiHeadAttention is only implemented for float32 and float16."); +} + +template Status UnfusedAttention( const cudaDeviceProp& device_prop, cublasHandle_t& cublas, @@ -624,6 +760,11 @@ Status UnfusedAttention( mask_index, mask_start, data.attention_bias, broadcast_attn_bias_dim_0, broadcast_attn_bias_dim_1, data.scratch, scratch2, parameters.is_unidirectional)); } else { // no mask + if (nullptr != data.output_qk) { + int64_t qk_size = (int64_t)batch_size * num_heads * sequence_length * total_sequence_length; + ORT_RETURN_IF_ERROR( + (CopyQK(stream, static_cast(qk_size), data.scratch, reinterpret_cast(data.output_qk)))); + } ORT_RETURN_IF_ERROR( ComputeSoftmax( stream, total_sequence_length, sequence_length, batch_size, num_heads, @@ -645,10 +786,170 @@ Status UnfusedAttention( // Temp_output is BxNxSxH_v, transpose to output BxSxNxH_v Status result = LaunchTransCtx(stream, sequence_length, batch_size, v_head_size, num_heads, device_prop.maxThreadsPerBlock, false, temp_output, data.output); + DUMP_TENSOR_D("Attention Output", data.output, batch_size, sequence_length, num_heads, v_head_size); return result; } +#ifndef USE_ROCM // exclude the following from hipify since they are not used in ROCM EP + template +Status ConcatPastToPresent(int batch_size, int num_heads, int qk_head_size, int v_head_size, + int sequence_length, int total_sequence_length, + cudaStream_t stream, int max_threads_per_block, + AttentionData& data) { + // Concat past key value to present (2xBxNxLxH), where L is kv_sequence_length and T is total_sequence_length. + // past_k (BxNxPxH) + k (BxNxLxH) => present_k (BxNxTxH) + // past_v (BxNxPxH) + v (BxNxLxH) => present_v (BxNxTxH) + // When there is past state, the head size for Q/K/V shall be same: H == H_v. + + if (nullptr != data.present) { // Attention op + assert(data.qkv_format == AttentionQkvFormat::Q_K_V_BNSH || + data.qkv_format == AttentionQkvFormat::Q_K_V_BNSH_QKV_BS3NH); + + ORT_RETURN_IF_ERROR( + LaunchConcatTensorToTensor( + stream, total_sequence_length, sequence_length, batch_size, qk_head_size, num_heads, + max_threads_per_block, 2, data.past, data.k, data.present)); + + + + // Update pointers to present_k and present_v. + data.k = data.present; + data.v = data.present + batch_size * num_heads * total_sequence_length * qk_head_size; + } else { // MultiHeadAttention op + if (nullptr != data.present_key) { + ORT_ENFORCE(data.qkv_format == AttentionQkvFormat::Q_K_V_BNSH || + data.qkv_format == AttentionQkvFormat::Q_K_V_BSNH_BNSH_BNSH); + if (nullptr != data.past_key) { + assert(data.past_key != data.k); + assert(data.past_value != data.v); + + ORT_RETURN_IF_ERROR( + LaunchConcatTensorToTensor(stream, total_sequence_length, sequence_length, + batch_size, qk_head_size, num_heads, + max_threads_per_block, 1, data.past_key, data.k, data.present_key)); + ORT_RETURN_IF_ERROR( + LaunchConcatTensorToTensor(stream, total_sequence_length, sequence_length, + batch_size, v_head_size, num_heads, + max_threads_per_block, 1, data.past_value, data.v, data.present_value)); + // Update pointers to present_k and present_v. + data.k = data.present_key; + data.v = data.present_value; + } else { // nullptr == data.past_key && nullptr != data.present_key + if (data.k != data.present_key) { + int64_t k_size = (int64_t)batch_size * num_heads * total_sequence_length * qk_head_size; + cudaMemcpyAsync(data.present_key, data.k, k_size * sizeof(T), cudaMemcpyDeviceToDevice, stream); + } + + if (data.v != data.present_value) { + int64_t v_size = (int64_t)batch_size * num_heads * total_sequence_length * v_head_size; + cudaMemcpyAsync(data.present_value, data.v, v_size * sizeof(T), cudaMemcpyDeviceToDevice, stream); + } + } + } + } + + return CUDA_CALL(cudaGetLastError()); +} + +// Template Instantiation +template Status ConcatPastToPresent(int batch_size, int num_heads, int qk_head_size, int v_head_size, + int sequence_length, int total_sequence_length, + cudaStream_t stream, + int max_threads_per_block, + AttentionData& data); + +template Status ConcatPastToPresent(int batch_size, int num_heads, int qk_head_size, int v_head_size, + int sequence_length, int total_sequence_length, + cudaStream_t stream, + int max_threads_per_block, + AttentionData& data); +#endif + +template +Status PastPresentBufferShare(int batch_size, int num_heads, int qk_head_size, int v_head_size, + int sequence_length, void* fused_runner, + contrib::AttentionParameters& parameters, + AttentionData& data, + cudaStream_t stream, + int max_threads_per_block) { + ORT_ENFORCE(qk_head_size == v_head_size); + assert(data.fused_cross_attention_kernel == nullptr); + assert(nullptr == fused_runner || parameters.is_unidirectional); + assert(!data.use_memory_efficient_attention); + assert(!data.use_flash_attention); + assert(data.has_qkv_workspace); + + bool combined_key_value = nullptr != data.present; + bool separate_key_value = nullptr != data.past_key && nullptr != data.present_key && + nullptr != data.past_value && nullptr != data.present_value; + + // Return early if buffer sharing is not possible + if (!combined_key_value && !separate_key_value) { + return Status::OK(); + } + + if (combined_key_value) { // Attention op + assert(data.gemm_buffer != nullptr); + + if (data.present != data.past) { + // For easy testing. Production should better avoid this path. + int64_t kv_size = 2LL * (int64_t)batch_size * num_heads * parameters.max_sequence_length * qk_head_size; + cudaMemcpyAsync(data.present, data.past, kv_size * sizeof(T), cudaMemcpyDeviceToDevice, stream); + } + + // For fused causal, bias has been added to gemm_buffer. + const T* bias = (nullptr != fused_runner && parameters.is_unidirectional) ? nullptr : data.bias; + + // append last k v to present + ORT_RETURN_IF_ERROR(LaunchAddBiasTransAppendKvToPresent( + stream, parameters.max_sequence_length, parameters.past_sequence_length, sequence_length, + batch_size, qk_head_size, num_heads, max_threads_per_block, + bias, data.gemm_buffer, data.present)); + + data.k = data.present; + data.v = data.present + batch_size * num_heads * parameters.max_sequence_length * qk_head_size; + } else if (data.use_decoder_masked_multihead_attention) { // DecoderMaskedMultiHeadAttention op + assert(data.qkv_format == AttentionQkvFormat::Q_K_V_BSNH || + data.qkv_format == AttentionQkvFormat::Q_K_V_BSNH_BNSH_BNSH); + + // DecoderMaskedMultiHeadAttention kernel manages the KV caches + // so this case is empty + } else { // MultiHeadAttention op + assert(data.qkv_format == AttentionQkvFormat::Q_K_V_BNSH || + data.qkv_format == AttentionQkvFormat::Q_K_V_BSNH_BNSH_BNSH); + assert(data.seqlens_k_total); + + // Using BNSH since AddBiasTranspose has already been applied + constexpr bool is_past_kv_bnsh_format = true; + constexpr bool is_new_kv_bnsh_format = true; + ORT_RETURN_IF_ERROR(LaunchConcatKVInPlace( + batch_size, num_heads, qk_head_size, parameters.max_sequence_length, + data.seqlens_k_total, nullptr, parameters.sequence_length, data.k, data.v, data.present_key, data.present_value, + is_past_kv_bnsh_format, is_new_kv_bnsh_format, stream, max_threads_per_block)); + + data.k = data.present_key; + data.v = data.present_value; + } + + return CUDA_CALL(cudaGetLastError()); +} + +template Status PastPresentBufferShare(int batch_size, int num_heads, int qk_head_size, int v_head_size, + int sequence_length, void* fused_runner, + contrib::AttentionParameters& parameters, + AttentionData& data, + cudaStream_t stream, + int max_threads_per_block); + +template Status PastPresentBufferShare(int batch_size, int num_heads, int qk_head_size, int v_head_size, + int sequence_length, void* fused_runner, + contrib::AttentionParameters& parameters, + AttentionData& data, + cudaStream_t stream, + int max_threads_per_block); + +template Status QkvToContext( const cudaDeviceProp& device_prop, cublasHandle_t& cublas, @@ -669,58 +970,36 @@ Status QkvToContext( // At most one fused kernel is enabled. assert((static_cast(data.use_flash_attention) + static_cast(data.use_memory_efficient_attention) + + static_cast(data.use_decoder_masked_multihead_attention) + static_cast(fused_runner != nullptr) + static_cast(data.fused_cross_attention_kernel != nullptr) + static_cast(data.kernel_type == AttentionKernelType::AttentionKernel_CudnnFlashAttention)) <= 1); + DUMP_STRING_INIT(); + DUMP_STRING("Preparing Q, K, V"); ORT_RETURN_IF_ERROR(PrepareQkv(parameters, data, stream, max_threads_per_block)); if (!parameters.past_present_share_buffer) { - ORT_RETURN_IF_ERROR(ConcatPastToPresent(batch_size, num_heads, qk_head_size, v_head_size, + ORT_RETURN_IF_ERROR(ConcatPastToPresent(batch_size, num_heads, qk_head_size, v_head_size, sequence_length, total_sequence_length, stream, max_threads_per_block, data)); } else { // past_present_share_buffer - assert(qk_head_size == v_head_size); - assert(data.fused_cross_attention_kernel == nullptr); - assert(nullptr == fused_runner || parameters.is_unidirectional); - assert(data.gemm_buffer != nullptr); - assert(!data.use_memory_efficient_attention); - assert(!data.use_flash_attention); - assert(data.has_qkv_workspace); - - if (nullptr != data.past_key || nullptr != data.present_key) { - // TODO: support this case. - ORT_THROW("buffer sharing for no bias case between past and present is not supported yet."); - } - - if (data.present != data.past) { - // For easy testing. Production should better avoid this path. - int64_t kv_size = 2LL * (int64_t)batch_size * num_heads * parameters.max_sequence_length * qk_head_size; - cudaMemcpyAsync(data.present, data.past, kv_size * sizeof(T), cudaMemcpyDeviceToDevice, stream); - } - - // For fused causal, bias has been added to gemm_buffer. - const T* bias = (nullptr != fused_runner && parameters.is_unidirectional) ? nullptr : data.bias; - - // append last k v to present - ORT_RETURN_IF_ERROR(LaunchAddBiasTransAppendKvToPresent( - stream, parameters.max_sequence_length, parameters.past_sequence_length, sequence_length, - batch_size, qk_head_size, num_heads, max_threads_per_block, - bias, data.gemm_buffer, data.present)); - - data.k = data.present; - data.v = data.present + batch_size * num_heads * parameters.max_sequence_length * qk_head_size; + ORT_RETURN_IF_ERROR(PastPresentBufferShare(batch_size, num_heads, qk_head_size, v_head_size, + sequence_length, fused_runner, + parameters, data, stream, max_threads_per_block)); } // Q, K and V are ready now if (data.fused_cross_attention_kernel != nullptr) { - return FusedTrtCrossAttention(stream, parameters, data); + DUMP_STRING("FusedTrtCrossAttention"); + return FusedTrtCrossAttention(stream, parameters, data); } // Run TRT fused attention. if (nullptr != fused_runner) { - return FusedTrtSelfAttention(stream, parameters, data); + DUMP_STRING("FusedTrtSelfAttention"); + return FusedTrtSelfAttention(stream, parameters, data); } // For raw attention mask, the scalar 1/sqrt(H) is moved to combine with softmax computation. @@ -728,27 +1007,37 @@ Status QkvToContext( : parameters.scale; #if USE_LEAN_ATTENTION if (data.use_lean_attention) { - return LeanAttention(device_prop, stream, parameters, data, scale); + DUMP_STRING("LeanAttention"); + return LeanAttention(device_prop, stream, parameters, data, scale); } #endif #if USE_FLASH_ATTENTION if (data.use_flash_attention) { - return FlashAttention(device_prop, stream, parameters, data, scale); + DUMP_STRING("FlashAttention"); + return FlashAttention(device_prop, stream, parameters, data, scale); } #endif if (data.kernel_type == AttentionKernelType::AttentionKernel_CudnnFlashAttention) { - return CudnnFlashAttention(cudnn, ort_stream, parameters, data, scale); + DUMP_STRING("CudnnFlashAttention"); + return CudnnFlashAttention(cudnn, ort_stream, parameters, data, scale); } #if USE_MEMORY_EFFICIENT_ATTENTION if (data.use_memory_efficient_attention) { - return EfficientAttention(device_prop, stream, parameters, data, scale); + DUMP_STRING("EfficientAttention"); + return EfficientAttention(device_prop, stream, parameters, data, scale); } #endif - return UnfusedAttention(device_prop, cublas, ort_stream, parameters, data, scale); + if (data.use_decoder_masked_multihead_attention) { + DUMP_STRING("DecoderMaskedMHA"); + return DecoderMaskedMultiHeadAttention(stream, parameters, data, scale); + } + + DUMP_STRING("UnfusedAttention"); + return UnfusedAttention(device_prop, cublas, ort_stream, parameters, data, scale); } // Template Instantiation @@ -772,6 +1061,42 @@ template Status QkvToContext( contrib::AttentionParameters& parameters, AttentionData& data); +template Status QkvToContext( + const cudaDeviceProp& device_prop, + cublasHandle_t& cublas, + cudnnHandle_t& cudnn, + Stream* ort_stream, + contrib::AttentionParameters& parameters, + AttentionData& data); + +template Status QkvToContext( + const cudaDeviceProp& device_prop, + cublasHandle_t& cublas, + cudnnHandle_t& cudnn, + Stream* ort_stream, + contrib::AttentionParameters& parameters, + AttentionData& data); + +template Status LaunchDecoderMaskedMultiHeadAttention( + const DecoderMaskedMultiHeadAttentionParameters& parameters, + cudaStream_t stream, + const int head_size); + +template Status LaunchDecoderMaskedMultiHeadAttention( + const DecoderMaskedMultiHeadAttentionParameters& parameters, + cudaStream_t stream, + const int head_size); + +template Status LaunchDecoderMaskedMultiHeadAttention( + const DecoderMaskedMultiHeadAttentionParameters& parameters, + cudaStream_t stream, + const int head_size); + +template Status LaunchDecoderMaskedMultiHeadAttention( + const DecoderMaskedMultiHeadAttentionParameters& parameters, + cudaStream_t stream, + const int head_size); + } // namespace cuda } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/attention_impl.h b/onnxruntime/contrib_ops/cuda/bert/attention_impl.h index 7d111a1ee21bf..14841b74daec8 100644 --- a/onnxruntime/contrib_ops/cuda/bert/attention_impl.h +++ b/onnxruntime/contrib_ops/cuda/bert/attention_impl.h @@ -11,6 +11,9 @@ #include "core/framework/allocator.h" #include "core/providers/cuda/cuda_common.h" #include "contrib_ops/cpu/bert/attention_common.h" +#include "contrib_ops/cpu/bert/attention_parameters.h" +#include "contrib_ops/cuda/bert/attention_data.h" +#include "contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_impl.h" namespace onnxruntime { namespace contrib { @@ -59,91 +62,6 @@ size_t GetAttentionWorkspaceSize( bool use_cudnn_flash_attention, bool no_qkv_workspace); -template -struct AttentionData { - T* gemm_buffer = nullptr; - const T* bias = nullptr; - - const T* query = nullptr; - const T* key = nullptr; - const T* value = nullptr; - const int* mask_index = nullptr; - gsl::span mask_index_dims; - const T* past = nullptr; - const T* past_key = nullptr; - const T* past_value = nullptr; - const T* attention_bias = nullptr; - - bool has_qkv_workspace = false; - T* workspace = nullptr; - - T* output = nullptr; - T* present = nullptr; - T* present_key = nullptr; - T* present_value = nullptr; - - void* fused_runner = nullptr; - const void* fused_cross_attention_kernel = nullptr; - - bool use_flash_attention = false; - bool use_memory_efficient_attention = false; - - const int32_t* cumulated_sequence_length_q_cache = nullptr; - const int32_t* cumulated_sequence_length_kv_cache = nullptr; - - // Intermediate data - T* q = nullptr; - T* k = nullptr; - T* v = nullptr; - T* scratch = nullptr; - AttentionQkvFormat qkv_format = AttentionQkvFormat::UNKNOWN; - - // Flash buffers - T* softmax_lse = nullptr; - T* softmax_lse_accum = nullptr; - T* out_accum = nullptr; - - // Flash Atttention and Lean Attention - int num_splits; - - // Lean Attention - bool use_lean_attention = false; -#if USE_LEAN_ATTENTION - int grid_dim_z = 0; - int max_tiles_per_tb = 0; - int high_load_tbs = 0; - int tiles_per_head = 0; - int* lean_sync_flag = nullptr; -#endif - - // For Debugging - size_t workspace_bytes = 0; - bool allow_debug_info = false; - - // For MultiHeadAttention only. - AttentionKernelType kernel_type = AttentionKernelType::AttentionKernel_Default; - AllocatorPtr allocator = nullptr; - bool IsUnfused() const { - return kernel_type == AttentionKernelType::AttentionKernel_Unfused; - } - - void PrintDebugInfo() const { - std::cout << "flash=" << use_flash_attention - << ", lean=" << use_lean_attention - << ", efficient=" << use_memory_efficient_attention - << ", fused_runner=" << (fused_runner != nullptr) - << ", fused_cross=" << (fused_cross_attention_kernel != nullptr) - << ", bias=" << (bias != nullptr) - << ", attn_bias=" << (attention_bias != nullptr) - << ", mask_dims=" << mask_index_dims.size() - << ", has_qkv_workspace=" << has_qkv_workspace - << ", workspace=" << workspace_bytes - << ", past=" << (past != nullptr ? 1 : (past_key != nullptr ? 2 : 0)) - << ", present=" << (present != nullptr ? 1 : (present_key != nullptr ? 2 : 0)) - << std::endl; - } -}; - // Return true if it does not need qkv workspace, false otherwise. template bool NoQkvWorkspace(contrib::AttentionParameters& parameters, AttentionData& data); @@ -154,7 +72,7 @@ Status PrepareQkv(contrib::AttentionParameters& parameters, cudaStream_t stream, int max_threads_per_block); -template +template Status QkvToContext( const cudaDeviceProp& device_prop, cublasHandle_t& cublas, @@ -163,6 +81,12 @@ Status QkvToContext( contrib::AttentionParameters& parameters, AttentionData& data); +template +Status LaunchDecoderMaskedMultiHeadAttention( + const DecoderMaskedMultiHeadAttentionParameters& parameters, + cudaStream_t stream, + const int head_size); + // BxNxSxH => BxSxNxH or SxBxNxH (reversed_bs is true) Status LaunchTransCtx(cudaStream_t stream, const int sequence_length, const int batch_size, const int head_size, const int num_heads, @@ -189,30 +113,6 @@ Status Transpose_BSNH_to_BNSH(const int batch_size, const int sequence_length, c Status Transpose_BSNH_to_BNSH(const int batch_size, const int sequence_length, const int num_heads, const int head_size, const half* input, half* output, cudaStream_t stream, const int max_threads_per_block); -Status LaunchConcatTensorToTensor(cudaStream_t stream, - const int all_sequence_length, - const int sequence_length, - const int batch_size, - const int head_size, - const int num_heads, - const int max_threads_per_block, - const int matrix_num, - const float* tensor_in, - const float* tensor_add, - float* tensor_out); - -Status LaunchConcatTensorToTensor(cudaStream_t stream, - const int all_sequence_length, - const int sequence_length, - const int batch_size, - const int head_size, - const int num_heads, - const int max_threads_per_block, - const int matrix_num, - const half* tensor_in, - const half* tensor_add, - half* tensor_out); - template Status ConcatPastToPresent(int batch_size, int num_heads, int qk_head_size, int v_head_size, int sequence_length, int total_sequence_length, @@ -221,17 +121,12 @@ Status ConcatPastToPresent(int batch_size, int num_heads, int qk_head_size, int AttentionData& data); template -Status LaunchAddBiasTransAppendKvToPresent(cudaStream_t stream, - const int max_sequence_length, - const int past_sequence_length, - const int sequence_length, - const int batch_size, - const int head_size, - const int num_heads, - const int max_threads_per_block, - const T* biases, - const T* qkv_buffer, - T* present); +Status PastPresentBufferShare(int batch_size, int num_heads, int qk_head_size, int v_head_size, + int sequence_length, void* fused_runner, + contrib::AttentionParameters& parameters, + AttentionData& data, + cudaStream_t stream, + int max_threads_per_block); template Status LaunchStridedCopy( diff --git a/onnxruntime/contrib_ops/cuda/bert/attention_kernel_options.cc b/onnxruntime/contrib_ops/cuda/bert/attention_kernel_options.cc index 8b8b764e7c785..1e0c9cb8baffd 100644 --- a/onnxruntime/contrib_ops/cuda/bert/attention_kernel_options.cc +++ b/onnxruntime/contrib_ops/cuda/bert/attention_kernel_options.cc @@ -23,10 +23,13 @@ void AttentionKernelOptions::Initialize(int value, bool use_build_flag, bool che use_efficient_attention_ = (value & static_cast(AttentionBackend::EFFICIENT_ATTENTION)) > 0; use_trt_fused_attention_ = (value & static_cast(AttentionBackend::TRT_FUSED_ATTENTION)) > 0; use_cudnn_flash_attention_ = (value & static_cast(AttentionBackend::CUDNN_FLASH_ATTENTION)) > 0; + use_unfused_ = (value & static_cast(AttentionBackend::MATH)) > 0; use_trt_flash_attention_ = (value & static_cast(AttentionBackend::TRT_FLASH_ATTENTION)) > 0; use_trt_cross_attention_ = (value & static_cast(AttentionBackend::TRT_CROSS_ATTENTION)) > 0; use_trt_causal_attention_ = (value & static_cast(AttentionBackend::TRT_CAUSAL_ATTENTION)) > 0; + + use_decoder_attention_ = (value & static_cast(AttentionBackend::DECODER_ATTENTION)) > 0; } else { use_flash_attention_ = !ParseEnvironmentVariableWithDefault(kDisableFlashAttention, false); #if USE_LEAN_ATTENTION @@ -40,6 +43,8 @@ void AttentionKernelOptions::Initialize(int value, bool use_build_flag, bool che use_trt_flash_attention_ = !ParseEnvironmentVariableWithDefault(kDisableTrtFlashAttention, false); use_trt_cross_attention_ = !ParseEnvironmentVariableWithDefault(kDisableFusedCrossAttention, false); use_trt_causal_attention_ = ParseEnvironmentVariableWithDefault(kEnableFusedCausalAttention, false); + + use_decoder_attention_ = !ParseEnvironmentVariableWithDefault(kDisableDecoderAttention, false); } enable_kernel_debug_info_ = ParseEnvironmentVariableWithDefault(kEnableAttentionKernelDebugInfo, false); @@ -100,6 +105,7 @@ void AttentionKernelOptions::Print() const { sstream << " TRT_FLASH_ATTENTION=" << int(use_trt_flash_attention_); sstream << " TRT_CROSS_ATTENTION=" << int(use_trt_cross_attention_); sstream << " TRT_CAUSAL_ATTENTION=" << int(use_trt_causal_attention_); + sstream << " DECODER_ATTENTION=" << int(use_decoder_attention_); sstream << " MATH=" << int(use_unfused_); if (!use_unfused_) { @@ -160,6 +166,8 @@ void AttentionKernelDebugInfo::Print(const char* operator_name, sstream << "TRT_CROSS_ATTENTION"; } else if (use_trt_causal_attention.has_value() && use_trt_causal_attention.value()) { sstream << "TRT_CAUSAL_ATTENTION"; + } else if (use_decoder_attention.has_value() && use_decoder_attention.value()) { + sstream << "DECODER_ATTENTION"; } else { sstream << "MATH"; } diff --git a/onnxruntime/contrib_ops/cuda/bert/attention_kernel_options.h b/onnxruntime/contrib_ops/cuda/bert/attention_kernel_options.h index caed704564c3b..fd3b90387a235 100644 --- a/onnxruntime/contrib_ops/cuda/bert/attention_kernel_options.h +++ b/onnxruntime/contrib_ops/cuda/bert/attention_kernel_options.h @@ -16,6 +16,7 @@ struct AttentionKernelDebugInfo { std::optional use_trt_flash_attention = std::nullopt; std::optional use_trt_cross_attention = std::nullopt; std::optional use_trt_causal_attention = std::nullopt; + std::optional use_decoder_attention = std::nullopt; void SetTrtFusedKernel(bool causal, bool enable_trt_flash_attention, int sequence_length); void Print(const char* operator_name, const std::string& node_name, bool is_float16, bool is_bfloat16) const; }; @@ -33,6 +34,7 @@ class AttentionKernelOptions { bool UseTrtFlashAttention() const { return use_trt_flash_attention_; } bool UseTrtCrossAttention() const { return use_trt_cross_attention_; } bool UseTrtCausalAttention() const { return use_trt_causal_attention_; } + bool UseDecoderAttention() const { return use_decoder_attention_; } bool AllowDebugInfo() const { return enable_kernel_debug_info_; } @@ -53,12 +55,12 @@ class AttentionKernelOptions { bool use_unfused_{true}; bool use_trt_flash_attention_{true}; - bool use_trt_cross_attention_{true}; - // Causal attention is disabled by default in #14732. bool use_trt_causal_attention_{false}; + bool use_decoder_attention_{true}; + bool enable_kernel_debug_info_{false}; int min_seq_len_for_flash_attention_packed_qkv_{0}; diff --git a/onnxruntime/contrib_ops/cuda/bert/attention_kv_cache.cu b/onnxruntime/contrib_ops/cuda/bert/attention_kv_cache.cu index 9f0f49348c225..1753929d60617 100644 --- a/onnxruntime/contrib_ops/cuda/bert/attention_kv_cache.cu +++ b/onnxruntime/contrib_ops/cuda/bert/attention_kv_cache.cu @@ -2,7 +2,7 @@ // Licensed under the MIT License. #include "contrib_ops/cuda/bert/attention_impl.h" -#include "core/providers/cuda/cuda_common.h" +#include "contrib_ops/cuda/bert/attention_kv_cache.h" #include "core/providers/cuda/cu_inc/common.cuh" using namespace onnxruntime::cuda; @@ -197,128 +197,9 @@ Status LaunchConcatTensorToTensor(cudaStream_t stream, return CUDA_CALL(cudaGetLastError()); } -Status LaunchConcatPastToPresent(cudaStream_t stream, - const int all_sequence_length, - const int sequence_length, - const int batch_size, - const int head_size, - const int num_heads, - const int max_threads_per_block, - const float* past, - const float* k_v, - float* present) { - return LaunchConcatTensorToTensor( - stream, - all_sequence_length, - sequence_length, - batch_size, - head_size, - num_heads, - max_threads_per_block, - 2, - past, - k_v, - present); -} - -Status LaunchConcatPastToPresent(cudaStream_t stream, - const int all_sequence_length, - const int sequence_length, - const int batch_size, - const int head_size, - const int num_heads, - const int max_threads_per_block, - const half* past, - const half* k_v, - half* present) { - return LaunchConcatTensorToTensor( - stream, - all_sequence_length, - sequence_length, - batch_size, - head_size, - num_heads, - max_threads_per_block, - 2, - past, - k_v, - present); -} #ifndef USE_ROCM // exclude the following from hipify since they are not used in ROCM EP -template -Status ConcatPastToPresent(int batch_size, int num_heads, int qk_head_size, int v_head_size, - int sequence_length, int total_sequence_length, - cudaStream_t stream, int max_threads_per_block, - AttentionData& data) { - // Concat past key value to present (2xBxNxLxH), where L is kv_sequence_length and T is total_sequence_length. - // past_k (BxNxPxH) + k (BxNxLxH) => present_k (BxNxTxH) - // past_v (BxNxPxH) + v (BxNxLxH) => present_v (BxNxTxH) - // When there is past state, the head size for Q/K/V shall be same: H == H_v. - - if (nullptr != data.present) { // Attention op - assert(data.qkv_format == AttentionQkvFormat::Q_K_V_BNSH || - data.qkv_format == AttentionQkvFormat::Q_K_V_BNSH_QKV_BS3NH); - - ORT_RETURN_IF_ERROR( - LaunchConcatPastToPresent( - stream, total_sequence_length, sequence_length, batch_size, qk_head_size, num_heads, - max_threads_per_block, data.past, data.k, data.present)); - - // Update pointers to present_k and present_v. - data.k = data.present; - data.v = data.present + batch_size * num_heads * total_sequence_length * qk_head_size; - } else { // MultiHeadAttention op - if (nullptr != data.present_key) { - ORT_ENFORCE(data.qkv_format == AttentionQkvFormat::Q_K_V_BNSH || - data.qkv_format == AttentionQkvFormat::Q_K_V_BSNH_BNSH_BNSH); - if (nullptr != data.past_key) { - assert(data.past_key != data.k); - assert(data.past_value != data.v); - - ORT_RETURN_IF_ERROR( - LaunchConcatTensorToTensor(stream, total_sequence_length, sequence_length, - batch_size, qk_head_size, num_heads, - max_threads_per_block, 1, data.past_key, data.k, data.present_key)); - ORT_RETURN_IF_ERROR( - LaunchConcatTensorToTensor(stream, total_sequence_length, sequence_length, - batch_size, v_head_size, num_heads, - max_threads_per_block, 1, data.past_value, data.v, data.present_value)); - // Update pointers to present_k and present_v. - data.k = data.present_key; - data.v = data.present_value; - } else { // nullptr == data.past_key && nullptr != data.present_key - if (data.k != data.present_key) { - int64_t k_size = (int64_t)batch_size * num_heads * total_sequence_length * qk_head_size; - cudaMemcpyAsync(data.present_key, data.k, k_size * sizeof(T), cudaMemcpyDeviceToDevice, stream); - } - - if (data.v != data.present_value) { - int64_t v_size = (int64_t)batch_size * num_heads * total_sequence_length * v_head_size; - cudaMemcpyAsync(data.present_value, data.v, v_size * sizeof(T), cudaMemcpyDeviceToDevice, stream); - } - } - } - } - - - return CUDA_CALL(cudaGetLastError()); -} - -// Template Instantiation -template Status ConcatPastToPresent(int batch_size, int num_heads, int qk_head_size, int v_head_size, - int sequence_length, int total_sequence_length, - cudaStream_t stream, - int max_threads_per_block, - AttentionData& data); - -template Status ConcatPastToPresent(int batch_size, int num_heads, int qk_head_size, int v_head_size, - int sequence_length, int total_sequence_length, - cudaStream_t stream, - int max_threads_per_block, - AttentionData& data); - // ---------------------------------------------------------------------------------- // Below kernels are for past and present sharing buffer // ---------------------------------------------------------------------------------- @@ -454,6 +335,382 @@ template Status LaunchAddBiasTransAppendKvToPresent(cudaStream_t stream, half* present); #endif +// Kernel to append new and past kv in either BSNH or BNSH format +// Adapted from ConcatTensorToTensor kernel in attention_kv_cache.cu file +template +__global__ void ConcatNewToPastKV(const int new_seqlen, + const int past_buffer_seqlen, + const T* past_kv, + const T* new_kv, + T* present_kv, + const int* seqlens_k, + const bool past_only, + // const int* seqlens_q, + const bool is_bsnh) { // refers to past; otherwise bnsh + const int h = threadIdx.x; + const int n = threadIdx.y; + const int s = blockIdx.x; + const int b = blockIdx.y; + + const int present_buffer_seqlen = gridDim.x; + const int num_heads = blockDim.y; + const int H = blockDim.x; + + const int present_batch_stride = present_buffer_seqlen * num_heads * H; + const int row_stride = is_bsnh ? num_heads * H : H; + const int present_head_stride = is_bsnh ? H : present_buffer_seqlen * H; + + // past_kv: BPNH or BNPH + // new_kv: BLNH + // present_kv: BTNH or BNTH, where T = P + L + + // prompt, token, and interactive decoding cases + const int past_seqlen = seqlens_k == nullptr ? 0 : seqlens_k[b] + 1 - new_seqlen; + + int out_offset = b * present_batch_stride + s * row_stride + n * present_head_stride + h; + if (s < past_seqlen) { + const int past_batch_stride = past_buffer_seqlen * num_heads * H; + const int past_head_stride = is_bsnh ? H : past_buffer_seqlen * H; + const int in_offset = b * past_batch_stride + s * row_stride + n * past_head_stride + h; + present_kv[out_offset] = past_kv[in_offset]; + } else if (!past_only && s < past_seqlen + new_seqlen) { + // Note: new KV always BSNH + const int new_batch_stride = new_seqlen * num_heads * H; + const int new_row_stride = num_heads * H; + const int new_head_stride = H; + const int in_offset = b * new_batch_stride + (s - past_seqlen) * new_row_stride + n * new_head_stride + h; + present_kv[out_offset] = new_kv[in_offset]; + } +} + +// Use when (H*)*num_heads > 1024 +template +__global__ void ConcatNewToPastKVLarge(const int new_seqlen, + const int past_buffer_seqlen, + const int H, + const int num_heads, + const T* past_kv, + const T* new_kv, + T* present_kv, + const int* seqlens_k, + const bool past_only, + const bool is_bsnh) { + int i = threadIdx.x + (blockDim.x * blockIdx.x); + if (i < H * num_heads) { + const int h = i % H; + const int n = i / H; + const int s = blockIdx.y; + const int b = blockIdx.z; + const int present_buffer_seqlen = gridDim.y; + + const int present_batch_stride = present_buffer_seqlen * num_heads * H; + const int row_stride = is_bsnh ? num_heads * H : H; + const int present_head_stride = is_bsnh ? H : present_buffer_seqlen * H; + + // past_kv: BPNH or BNPH + // new_kv: BLNH + // present_kv: BTNH or BNTH, where T = P + L + + // prompt, token, and interactive decoding cases + const int past_seqlen = seqlens_k == nullptr ? 0 : seqlens_k[b] + 1 - new_seqlen; + + int out_offset = b * present_batch_stride + s * row_stride + n * present_head_stride + h; + if (s < past_seqlen) { + const int past_batch_stride = past_buffer_seqlen * num_heads * H; + const int past_head_stride = is_bsnh ? H : past_buffer_seqlen * H; + const int in_offset = b * past_batch_stride + s * row_stride + n * past_head_stride + h; + present_kv[out_offset] = past_kv[in_offset]; + } else if (!past_only && s < past_seqlen + new_seqlen) { + const int new_batch_stride = new_seqlen * num_heads * H; + const int new_row_stride = num_heads * H; + const int new_head_stride = H; + const int in_offset = b * new_batch_stride + (s - past_seqlen) * new_row_stride + n * new_head_stride + h; + present_kv[out_offset] = new_kv[in_offset]; + } + } +} + +// Concat new to kv buffer in place +template +Status LaunchConcatNewToPastKV(const int batch_size, + const int kv_num_heads, + const int head_size, + const int kv_sequence_length, + const int past_sequence_length, + const int present_sequence_length, + const bool is_bsnh, + const int* seqlens_k, + const T* past_key, + const T* past_value, + const T* new_key, + const T* new_value, + T* present_key, + T* present_value, + cudaStream_t stream, + const int max_threads_per_block, + const bool past_only) { + const int H = head_size / 4; // divide by 4 so kernel can operate on 4 float16 elements at a time. + if (H * kv_num_heads <= max_threads_per_block) { + const dim3 grid(present_sequence_length, batch_size, 1); + const dim3 block(H, kv_num_heads, 1); + ConcatNewToPastKV<<>>(kv_sequence_length, + past_sequence_length, + reinterpret_cast(past_key), + reinterpret_cast(new_key), + reinterpret_cast(present_key), + seqlens_k, + past_only, + is_bsnh); + ConcatNewToPastKV<<>>(kv_sequence_length, + past_sequence_length, + reinterpret_cast(past_value), + reinterpret_cast(new_value), + reinterpret_cast(present_value), + seqlens_k, + past_only, + is_bsnh); + } else { + int steps = (H * kv_num_heads + 255) / 256; + const dim3 grid(steps, present_sequence_length, batch_size); + const dim3 block(256, 1, 1); + ConcatNewToPastKVLarge<<>>(kv_sequence_length, + past_sequence_length, + H, + kv_num_heads, + reinterpret_cast(past_key), + reinterpret_cast(new_key), + reinterpret_cast(present_key), + seqlens_k, + past_only, + is_bsnh); + ConcatNewToPastKVLarge<<>>(kv_sequence_length, + past_sequence_length, + H, + kv_num_heads, + reinterpret_cast(past_value), + reinterpret_cast(new_value), + reinterpret_cast(present_value), + seqlens_k, + past_only, + is_bsnh); + } + return CUDA_CALL(cudaGetLastError()); +} + +template Status LaunchConcatNewToPastKV(const int batch_size, + const int kv_num_heads, + const int head_size, + const int kv_sequence_length, + const int past_sequence_length, + const int present_sequence_length, + const bool is_bsnh, + const int* seqlens_k, + const half* past_key, + const half* past_value, + const half* new_key, + const half* new_value, + half* present_key, + half* present_value, + cudaStream_t stream, + const int max_threads_per_block, + const bool past_only); + +template Status LaunchConcatNewToPastKV(const int batch_size, + const int kv_num_heads, + const int head_size, + const int kv_sequence_length, + const int past_sequence_length, + const int present_sequence_length, + const bool is_bsnh, + const int* seqlens_k, + const BFloat16* past_key, + const BFloat16* past_value, + const BFloat16* new_key, + const BFloat16* new_value, + BFloat16* present_key, + BFloat16* present_value, + cudaStream_t stream, + const int max_threads_per_block, + const bool past_only); + +// Kernel to append new kv to kv buffer in place +template +__global__ void ConcatKVInPlace(const int max_seqlen, + T* kv_buff, + const T* new_kv, + const int* seqlens_k, + const int* total_seqlens_k, + const bool is_past_kv_bnsh_format, + const bool is_new_kv_bnsh_format) { + const int h = threadIdx.x; + const int n = threadIdx.y; + const int s = blockIdx.x; + const int b = blockIdx.y; + + const int new_seqlen = gridDim.x; + const int kv_num_heads = blockDim.y; + const int H = blockDim.x; + + const int past_seq_len = (total_seqlens_k != nullptr) + ? (total_seqlens_k[b] - new_seqlen) + : (seqlens_k == nullptr ? 0 : (seqlens_k[b] + 1 - new_seqlen)); + + int out_offset = is_past_kv_bnsh_format + ? INDEX_4D(kv_num_heads, max_seqlen, H, b, n, s + past_seq_len, h) + : INDEX_4D(max_seqlen, kv_num_heads, H, b, s + past_seq_len, n, h); + + int in_offset = is_new_kv_bnsh_format + ? INDEX_4D(kv_num_heads, new_seqlen, H, b, n, s, h) + : INDEX_4D(new_seqlen, kv_num_heads, H, b, s, n, h); + + kv_buff[out_offset] = new_kv[in_offset]; +} + +template +__global__ void ConcatKVInPlaceLarge(const int max_seqlen, + const int H, + const int kv_num_heads, + T* kv_buff, + const T* new_kv, + const int* seqlens_k, + const int* total_seqlens_k, + const bool is_past_kv_bnsh_format, + const bool is_new_kv_bnsh_format) { // refers to kv buff; otherwise bnsh + int i = threadIdx.x + (blockDim.x * blockIdx.x); + if (i < H * kv_num_heads) { + const int h = i % H; + const int n = i / H; + const int s = blockIdx.y; + const int b = blockIdx.z; + const int new_seqlen = gridDim.y; + const int past_seq_len = (total_seqlens_k != nullptr) + ? (total_seqlens_k[b] - new_seqlen) + : (seqlens_k == nullptr ? 0 : (seqlens_k[b] + 1 - new_seqlen)); + + int out_offset = is_past_kv_bnsh_format + ? INDEX_4D(kv_num_heads, max_seqlen, H, b, n, s + past_seq_len, h) + : INDEX_4D(max_seqlen, kv_num_heads, H, b, s + past_seq_len, n, h); + + int in_offset = is_new_kv_bnsh_format + ? INDEX_4D(kv_num_heads, new_seqlen, H, b, n, s, h) + : INDEX_4D(new_seqlen, kv_num_heads, H, b, s, n, h); + + kv_buff[out_offset] = new_kv[in_offset]; + } +} + +// Concat new to kv buffer in place +template +Status LaunchConcatKVInPlace(int batch_size, + int kv_num_heads, + int head_size, + int max_sequence_length, + const int* seqlens_k, + const int* total_seqlens_k, + int new_seq_len, + const T* new_key, + const T* new_value, + T* present_key, + T* present_value, + const bool is_past_kv_bnsh_format, + const bool is_new_kv_bnsh_format, + cudaStream_t stream, + const int max_threads_per_block) { + // static_assert(sizeof(T) == 2); + assert(head_size % 4 == 0); + + const int H = head_size / 4; + if (H * kv_num_heads <= max_threads_per_block) { + const dim3 grid(new_seq_len, batch_size, 1); + const dim3 block(H, kv_num_heads, 1); + ConcatKVInPlace<<>>(max_sequence_length, + reinterpret_cast(present_key), + reinterpret_cast(new_key), + seqlens_k, + total_seqlens_k, + is_past_kv_bnsh_format, + is_new_kv_bnsh_format); + ConcatKVInPlace<<>>(max_sequence_length, + reinterpret_cast(present_value), + reinterpret_cast(new_value), + seqlens_k, + total_seqlens_k, + is_past_kv_bnsh_format, + is_new_kv_bnsh_format); + } else { + int steps = int(ceil(float(H * kv_num_heads) / 256.0)); + const dim3 grid(steps, new_seq_len, batch_size); + const dim3 block(256, 1, 1); + ConcatKVInPlaceLarge<<>>(max_sequence_length, + H, + kv_num_heads, + reinterpret_cast(present_key), + reinterpret_cast(new_key), + seqlens_k, + total_seqlens_k, + is_past_kv_bnsh_format, + is_new_kv_bnsh_format); + ConcatKVInPlaceLarge<<>>(max_sequence_length, + H, + kv_num_heads, + reinterpret_cast(present_value), + reinterpret_cast(new_value), + seqlens_k, + total_seqlens_k, + is_past_kv_bnsh_format, + is_new_kv_bnsh_format); + } + return CUDA_CALL(cudaGetLastError()); +} + +template Status LaunchConcatKVInPlace(int batch_size, + int kv_num_heads, + int head_size, + int max_sequence_length, + const int* seqlens_k, + const int* total_seqlens_k, + int new_seq_len, + const half* new_key, + const half* new_value, + half* present_key, + half* present_value, + bool is_past_kv_bnsh_format, + bool is_new_kv_bnsh_format, + cudaStream_t stream, + const int max_threads_per_block); + +template Status LaunchConcatKVInPlace(int batch_size, + int kv_num_heads, + int head_size, + int max_sequence_length, + const int* seqlens_k, + const int* total_seqlens_k, + int new_seq_len, + const BFloat16* new_key, + const BFloat16* new_value, + BFloat16* present_key, + BFloat16* present_value, + bool is_past_kv_bnsh_format, + bool is_new_kv_bnsh_format, + cudaStream_t stream, + const int max_threads_per_block); + +template Status LaunchConcatKVInPlace(int batch_size, + int kv_num_heads, + int head_size, + int max_sequence_length, + const int* seqlens_k, + const int* total_seqlens_k, + int new_seq_len, + const float* new_key, + const float* new_value, + float* present_key, + float* present_value, + bool is_past_kv_bnsh_format, + bool is_new_kv_bnsh_format, + cudaStream_t stream, + const int max_threads_per_block); + } // namespace cuda } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/attention_kv_cache.h b/onnxruntime/contrib_ops/cuda/bert/attention_kv_cache.h new file mode 100644 index 0000000000000..94104e8b6a5d6 --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/attention_kv_cache.h @@ -0,0 +1,92 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include "core/providers/cuda/shared_inc/cuda_utils.h" +#include +#include "core/framework/allocator.h" +#include "core/providers/cuda/cuda_common.h" + +// Macro to help compute index of flatten 4D matrix, note that dim1 is not used so it is excluded. +#define INDEX_4D(dim2, dim3, dim4, i, j, k, l) ((i) * (dim2) * (dim3) * (dim4) + (j) * (dim3) * (dim4) + (k) * (dim4) + (l)) + +namespace onnxruntime { +namespace contrib { +namespace cuda { + +Status LaunchConcatTensorToTensor(cudaStream_t stream, + const int all_sequence_length, + const int sequence_length, + const int batch_size, + const int head_size, + const int num_heads, + const int max_threads_per_block, + const int matrix_num, + const float* tensor_in, + const float* tensor_add, + float* tensor_out); + +Status LaunchConcatTensorToTensor(cudaStream_t stream, + const int all_sequence_length, + const int sequence_length, + const int batch_size, + const int head_size, + const int num_heads, + const int max_threads_per_block, + const int matrix_num, + const half* tensor_in, + const half* tensor_add, + half* tensor_out); + +template +Status LaunchAddBiasTransAppendKvToPresent(cudaStream_t stream, + const int max_sequence_length, + const int past_sequence_length, + const int sequence_length, + const int batch_size, + const int head_size, + const int num_heads, + const int max_threads_per_block, + const T* biases, + const T* qkv_buffer, + T* present); + +template +Status LaunchConcatNewToPastKV(const int batch_size, + const int kv_num_heads, + const int head_size, + const int kv_sequence_length, + const int past_sequence_length, + const int present_sequence_length, + const bool is_bsnh, + const int* seqlens_k, + const T* past_key, + const T* past_value, + const T* new_key, + const T* new_value, + T* present_key, + T* present_value, + cudaStream_t stream, + const int max_threads_per_block, + const bool past_only); + +template +Status LaunchConcatKVInPlace(int batch_size, + int kv_num_heads, + int head_size, + int max_sequence_length, // max sequence length of present_key or present_value. + const int* seqlens_k, // it is not used when total_seqlens_k is available. + const int* total_seqlens_k, // optional, nullptr means it is not available. + int new_seq_len, + const T* new_key, + const T* new_value, + T* present_key, + T* present_value, + bool is_past_kv_bnsh_format, + bool is_new_kv_bnsh_format, + cudaStream_t stream, + const int max_threads_per_block); + +} // namespace cuda +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/attention_prepare_qkv.cu b/onnxruntime/contrib_ops/cuda/bert/attention_prepare_qkv.cu index 282ba2403b135..122e94d9558e3 100644 --- a/onnxruntime/contrib_ops/cuda/bert/attention_prepare_qkv.cu +++ b/onnxruntime/contrib_ops/cuda/bert/attention_prepare_qkv.cu @@ -12,10 +12,10 @@ namespace onnxruntime { namespace contrib { namespace cuda { -#if DEBUG_TENSOR_LEVEL > 1 +#if DUMP_TENSOR_LEVEL > 1 // Dump the workspace for Q, K, V after processing QKV data. template -void DumpQkv(AttentionData& data) { +void DumpQkv(contrib::AttentionParameters& parameters, AttentionData& data) { const int batch_size = parameters.batch_size; const int sequence_length = parameters.sequence_length; const int kv_sequence_length = parameters.kv_sequence_length; @@ -33,7 +33,7 @@ void DumpQkv(AttentionData& data) { DUMP_TENSOR_D("k(BSNH)", data.k, batch_size, kv_sequence_length, num_heads, qk_head_size); DUMP_TENSOR_D("v(BSNH)", data.v, batch_size, kv_sequence_length, num_heads, v_head_size); } else if (data.qkv_format == AttentionQkvFormat::Q_K_V_BSNH_BNSH_BNSH) { - DUMP_TENSOR_D("q(BNSH)", data.q, batch_size, num_heads, sequence_length, qk_head_size); + DUMP_TENSOR_D("q(BSNH)", data.q, batch_size, sequence_length, num_heads, qk_head_size); DUMP_TENSOR_D("k(BNSH)", data.k, batch_size, num_heads, kv_sequence_length, qk_head_size); DUMP_TENSOR_D("v(BNSH)", data.v, batch_size, num_heads, kv_sequence_length, v_head_size); } else if (data.qkv_format == AttentionQkvFormat::QKV_BSN3H) { @@ -52,23 +52,25 @@ void DumpInputs(contrib::AttentionParameters& parameters, AttentionData& data const int v_head_size = parameters.v_head_size; DUMP_TENSOR_INIT(); - if (parameters.qkv_format == AttentionQkvFormat::Q_K_V_BSNH) { - DUMP_TENSOR_D("Query(BNSH)", data.query, batch_size, num_heads, sequence_length, qk_head_size); - DUMP_TENSOR_D("Key(BNSH)", data.key, batch_size, num_heads, kv_sequence_length, qk_head_size); - DUMP_TENSOR_D("Value(BNSH)", data.value, batch_size, num_heads, kv_sequence_length, v_head_size); - } else if (data.qkv_format == AttentionQkvFormat::Q_K_V_BSNH) { - DUMP_TENSOR_D("Query(BSNH)", data.query, batch_size, sequence_length, num_heads, qk_head_size); - DUMP_TENSOR_D("Key(BSNH)", data.key, batch_size, kv_sequence_length, num_heads, qk_head_size); - DUMP_TENSOR_D("Value(BSNH)", data.value, batch_size, kv_sequence_length, num_heads, v_head_size); - } else if (data.qkv_format == AttentionQkvFormat::Q_K_V_BSNH_BNSH_BNSH) { - DUMP_TENSOR_D("Query(BNSH)", data.query, batch_size, num_heads, sequence_length, qk_head_size); - DUMP_TENSOR_D("Key(BNSH)", data.key, batch_size, num_heads, kv_sequence_length, qk_head_size); - DUMP_TENSOR_D("Value(BNSH)", data.value, batch_size, num_heads, kv_sequence_length, v_head_size); - } else if (data.qkv_format == AttentionQkvFormat::QKV_BSN3H) { - DUMP_TENSOR_D("Query(BSN3H)", data.query, batch_size, sequence_length, num_heads * 3, qk_head_size); - } else if (data.qkv_format == AttentionQkvFormat::Q_KV_BSNH_BSN2H) { - DUMP_TENSOR_D("Query(BNSH)", data.query, batch_size, num_heads, sequence_length, qk_head_size); - DUMP_TENSOR_D("Value(BSN2H)", data.value, batch_size, sequence_length, num_heads * 2, qk_head_size); + if (data.gemm_buffer == nullptr) { // MultiHeadAttention + if (parameters.qkv_format == AttentionQkvFormat::Q_K_V_BNSH) { + DUMP_TENSOR_D("Query(BNSH)", data.query, batch_size, num_heads, sequence_length, qk_head_size); + DUMP_TENSOR_D("Key(BNSH)", data.key, batch_size, num_heads, kv_sequence_length, qk_head_size); + DUMP_TENSOR_D("Value(BNSH)", data.value, batch_size, num_heads, kv_sequence_length, v_head_size); + } else if (parameters.qkv_format == AttentionQkvFormat::Q_K_V_BSNH) { + DUMP_TENSOR_D("Query(BSNH)", data.query, batch_size, sequence_length, num_heads, qk_head_size); + DUMP_TENSOR_D("Key(BSNH)", data.key, batch_size, kv_sequence_length, num_heads, qk_head_size); + DUMP_TENSOR_D("Value(BSNH)", data.value, batch_size, kv_sequence_length, num_heads, v_head_size); + } else if (parameters.qkv_format == AttentionQkvFormat::Q_K_V_BSNH_BNSH_BNSH) { + DUMP_TENSOR_D("Query(BSNH)", data.query, batch_size, sequence_length, num_heads, qk_head_size); + DUMP_TENSOR_D("Key(BNSH)", data.key, batch_size, num_heads, kv_sequence_length, qk_head_size); + DUMP_TENSOR_D("Value(BNSH)", data.value, batch_size, num_heads, kv_sequence_length, v_head_size); + } else if (parameters.qkv_format == AttentionQkvFormat::QKV_BSN3H) { + DUMP_TENSOR_D("Query(BSN3H)", data.query, batch_size, sequence_length, num_heads * 3, qk_head_size); + } else if (parameters.qkv_format == AttentionQkvFormat::Q_KV_BSNH_BSN2H) { + DUMP_TENSOR_D("Query(BSNH)", data.query, batch_size, sequence_length, num_heads, qk_head_size); + DUMP_TENSOR_D("Key(BSN2H)", data.key, batch_size, sequence_length, num_heads * 2, qk_head_size); + } } if (data.bias != nullptr) { @@ -99,7 +101,7 @@ void DumpInputs(contrib::AttentionParameters& parameters, AttentionData& data // Dump the kernel outputs template -void DumpOutputs(AttentionData& data) { +void DumpOutputs(contrib::AttentionParameters& parameters, AttentionData& data) { DUMP_TENSOR_INIT(); DUMP_TENSOR("output", data.output, parameters.batch_size, parameters.sequence_length, parameters.num_heads, parameters.v_head_size); @@ -193,9 +195,22 @@ Status PrepareQkv_MHA_Cross(contrib::AttentionParameters& parameters, data.q = const_cast(data.query); } - // Here we have assumption that there is no bias for key and value when they are in BNSH format. + // Here we assume that there is no bias for key and value when they are in BNSH format. data.k = const_cast(data.key); data.v = const_cast(data.value); + data.qkv_format = AttentionQkvFormat::Q_K_V_BSNH_BNSH_BNSH; + } else if (data.use_decoder_masked_multihead_attention) { + assert(data.attention_bias == nullptr); + + data.q = const_cast(data.query); + data.k = const_cast(data.key); + data.v = const_cast(data.value); + + // Here we assume that there is no bias for key and value when they are in BNSH format. + data.q_bias = const_cast(data.bias); + data.k_bias = nullptr; + data.v_bias = nullptr; + data.qkv_format = AttentionQkvFormat::Q_K_V_BSNH_BNSH_BNSH; } else { // unfused kernel assert(data.IsUnfused()); @@ -455,6 +470,16 @@ Status PrepareQkv_MHA_WithPast_Bias(contrib::AttentionParameters& parameters, data.value, data.bias + 2 * num_heads * qk_head_size, data.v, true, -1); data.qkv_format = AttentionQkvFormat::Q_K_V_BSNH_BNSH_BNSH; + } else if (data.use_decoder_masked_multihead_attention) { + data.q = const_cast(data.query); + data.k = const_cast(data.key); + data.v = const_cast(data.value); + + data.q_bias = const_cast(data.bias); + data.k_bias = const_cast(data.bias + parameters.hidden_size); + data.v_bias = const_cast(data.bias + 2LL * parameters.hidden_size); + + data.qkv_format = AttentionQkvFormat::Q_K_V_BSNH; } else { // unfused kernel assert(data.IsUnfused()); @@ -628,24 +653,31 @@ Status PrepareQkv_MultiHeadAttention(contrib::AttentionParameters& parameters, AttentionData& data, cudaStream_t stream, int max_threads_per_block) { + DUMP_STRING_INIT(); switch (parameters.qkv_format) { case AttentionQkvFormat::Q_K_V_BSNH_BNSH_BNSH: + DUMP_STRING("PrepareQkv_MHA_Cross"); ORT_RETURN_IF_ERROR(PrepareQkv_MHA_Cross(parameters, data, stream, max_threads_per_block)); break; case AttentionQkvFormat::Q_KV_BSNH_BSN2H: + DUMP_STRING("PrepareQkv_MHA_PackedKV"); ORT_RETURN_IF_ERROR(PrepareQkv_MHA_PackedKV(parameters, data, stream, max_threads_per_block)); break; case AttentionQkvFormat::QKV_BSN3H: + DUMP_STRING("PrepareQkv_MHA_PackedQKV"); ORT_RETURN_IF_ERROR(PrepareQkv_MHA_PackedQKV(parameters, data, stream, max_threads_per_block)); break; case AttentionQkvFormat::Q_K_V_BSNH: if (data.past_key != nullptr || data.present_key != nullptr) { if (data.bias == nullptr) { + DUMP_STRING("PrepareQkv_MHA_WithPast_NoBias"); ORT_RETURN_IF_ERROR(PrepareQkv_MHA_WithPast_NoBias(parameters, data, stream, max_threads_per_block)); } else { + DUMP_STRING("PrepareQkv_MHA_WithPast_Bias"); ORT_RETURN_IF_ERROR(PrepareQkv_MHA_WithPast_Bias(parameters, data, stream, max_threads_per_block)); } } else { // no past state + DUMP_STRING("PrepareQkv_MHA_NoPast"); ORT_RETURN_IF_ERROR(PrepareQkv_MHA_NoPast(parameters, data, stream, max_threads_per_block)); } break; @@ -705,7 +737,9 @@ Status PrepareQkv(contrib::AttentionParameters& parameters, data.scratch = data.workspace; } -#if DEBUG_TENSOR_LEVEL > 1 +#if DUMP_TENSOR_LEVEL > 1 + DUMP_STRING_INIT(); + DUMP_STRING("Dump Inputs Before PrepareQkv..."); DumpInputs(parameters, data); #endif @@ -717,8 +751,9 @@ Status PrepareQkv(contrib::AttentionParameters& parameters, assert(data.qkv_format != AttentionQkvFormat::UNKNOWN); -#if DEBUG_TENSOR_LEVEL > 1 - DumpQkv(data); +#if DUMP_TENSOR_LEVEL > 1 + DUMP_STRING("Dump Inputs After PrepareQkv..."); + DumpQkv(parameters, data); #endif CUDA_RETURN_IF_ERROR(cudaGetLastError()); diff --git a/onnxruntime/contrib_ops/cuda/bert/attention_qk.cu b/onnxruntime/contrib_ops/cuda/bert/attention_qk.cu new file mode 100644 index 0000000000000..3f02a441da73e --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/attention_qk.cu @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/cuda/cu_inc/common.cuh" +#include "contrib_ops/cuda/bert/attention_qk.h" + +using namespace onnxruntime::cuda; + +namespace onnxruntime { +namespace contrib { +namespace cuda { + +__global__ void ConvertAndCopyQK(const int count, const float* input, half* output) { + int idx = threadIdx.x + blockIdx.x * blockDim.x; + if (idx < count) { + output[idx] = __float2half(input[idx]); + } +} + +__global__ void ConvertAndCopyQK(const int count, const half* input, float* output) { + int idx = threadIdx.x + blockIdx.x * blockDim.x; + if (idx < count) { + output[idx] = __half2float(input[idx]); + } +} + +template +__global__ void ConvertAndCopyQK(const int count, const T* input, T* output) { + int idx = threadIdx.x + blockIdx.x * blockDim.x; + if (idx < count) { + output[idx] = input[idx]; + } +} + +template +Status CopyQK(cudaStream_t stream, + const int qk_size, + const T* input, + QK* output) { + constexpr const bool half2float = std::is_same::value && std::is_same::value; + constexpr const bool float2half = std::is_same::value && std::is_same::value; + static_assert(half2float || float2half, "This function supports either or "); + + constexpr const int block_size = 256; + int num_blocks = (qk_size + block_size - 1) / block_size; + ConvertAndCopyQK<<>>(qk_size, input, output); + + return CUDA_CALL(cudaGetLastError()); +} + +template Status CopyQK(cudaStream_t stream, + const int qk_size, + const float* input, + half* output); + +template Status CopyQK(cudaStream_t stream, + const int qk_size, + const half* input, + float* output); + +template <> +Status CopyQK(cudaStream_t stream, + const int qk_size, + const float* input, + float* output) { + CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(output, input, qk_size * sizeof(float), cudaMemcpyDeviceToDevice, stream)); + return Status::OK(); +} + +template <> +Status CopyQK(cudaStream_t stream, + const int qk_size, + const half* input, + half* output) { + CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(output, input, qk_size * sizeof(half), cudaMemcpyDeviceToDevice, stream)); + return Status::OK(); +} + +} // namespace cuda +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/attention_qk.h b/onnxruntime/contrib_ops/cuda/bert/attention_qk.h new file mode 100644 index 0000000000000..3dead308e7d17 --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/attention_qk.h @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/cuda/shared_inc/cuda_utils.h" +#include +#include "core/framework/allocator.h" +#include "core/providers/cuda/cuda_common.h" + +namespace onnxruntime { +namespace contrib { +namespace cuda { + +template +Status CopyQK(cudaStream_t stream, + const int qk_size, + const T* input, + QK* output); + +} // namespace cuda +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/attention_softmax.cu b/onnxruntime/contrib_ops/cuda/bert/attention_softmax.cu index 52f94247a8b2b..04bb571f43fa3 100644 --- a/onnxruntime/contrib_ops/cuda/bert/attention_softmax.cu +++ b/onnxruntime/contrib_ops/cuda/bert/attention_softmax.cu @@ -49,14 +49,15 @@ namespace attention_softmax_cuda { // grid size is (num_heads * sequence_length, batch_size, 1) // input and output shape is (batch_size, num_heads, sequence_length, total_sequence_length) // bias shape is (batch_size or 1, num_heads or 1, sequence_length, total_sequence_length) -#define DECLARE_SOFTMAX_VARS() \ - [[maybe_unused]] const int s = blockIdx.x % sequence_length; \ - const int b = blockIdx.y; \ - int64_t offset = static_cast(b * gridDim.x + blockIdx.x) * static_cast(total_sequence_length); \ - [[maybe_unused]] int64_t bias_offset = 0; \ - if constexpr (HAS_BIAS) { \ - const int j = (broadcast_attn_bias_dim_0 ? 0 : (b * gridDim.x)) + (broadcast_attn_bias_dim_1 ? s : blockIdx.x); \ - bias_offset = static_cast(j) * static_cast(total_sequence_length); \ +#define DECLARE_SOFTMAX_VARS() \ + [[maybe_unused]] const int s = blockIdx.x % sequence_length; \ + const int b = blockIdx.y; \ + int64_t offset = static_cast(b * gridDim.x + blockIdx.x) * static_cast(total_sequence_length); \ + [[maybe_unused]] int64_t bias_offset = 0; \ + if constexpr (HAS_BIAS) { \ + const int j = (broadcast_attn_bias_dim_0 ? 0 : (b * (broadcast_attn_bias_dim_1 ? sequence_length : gridDim.x))) + \ + (broadcast_attn_bias_dim_1 ? s : blockIdx.x); \ + bias_offset = static_cast(j) * static_cast(total_sequence_length); \ } // This kernel is for non causal, attention mask 1D or None, and total_sequence_length > 1024. diff --git a/onnxruntime/contrib_ops/cuda/bert/attention_softmax.h b/onnxruntime/contrib_ops/cuda/bert/attention_softmax.h index f7fab268b4607..126de15362761 100644 --- a/onnxruntime/contrib_ops/cuda/bert/attention_softmax.h +++ b/onnxruntime/contrib_ops/cuda/bert/attention_softmax.h @@ -9,14 +9,14 @@ namespace attention_softmax_cuda { template Status ComputeSoftmax(cudaStream_t stream, const int all_sequence_length, const int sequence_length, - const int batch_size, const int num_heads, const T* rel_pos_bias, + const int batch_size, const int num_heads, const T* attn_bias, const bool broadcast_attn_bias_dim_0, const bool broadcast_attn_bias_dim_1, T* input, T* output, bool causal); template Status ComputeSoftmaxWithCumSeqLength( const T* input, - const T* rel_pos_bias, + const T* attn_bias, const bool broadcast_attn_bias_dim_0, const bool broadcast_attn_bias_dim_1, const int32_t* cum_seq_length, @@ -34,7 +34,7 @@ Status ComputeSoftmaxWithMask1D(cudaStream_t stream, const int num_heads, const int* mask_index, const int* mask_start, - const T* rel_pos_bias, + const T* attn_bias, const bool broadcast_attn_bias_dim_0, const bool broadcast_attn_bias_dim_1, const T* input, @@ -49,7 +49,7 @@ Status ComputeSoftmaxWithRawMask(Stream* ort_stream, const int num_heads, const int* attention_mask, const bool* key_padding_mask, - const T* rel_pos_bias, + const T* attn_bias, const bool broadcast_attn_bias_dim_0, const bool broadcast_attn_bias_dim_1, const T* input, diff --git a/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/fmha_launch_template.h b/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/fmha_launch_template.h index 9b3ba73254d73..8d8f735e3ed34 100644 --- a/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/fmha_launch_template.h +++ b/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/fmha_launch_template.h @@ -222,6 +222,9 @@ void LaunchCutlassFmha(const MemoryEfficientAttentionParams& params) { } p.use_smooth_softmax = params.use_smooth_softmax; + + // local_windows_size in GQA does not include current query token, while windows_size in this kernel includes it. + p.window_size = params.local_window_size + 1; } auto kernel_fn = attention_kernel_batched_impl; diff --git a/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/kernel_forward.h b/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/kernel_forward.h index 8dff521da48d1..f35d6c2e6c8dc 100644 --- a/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/kernel_forward.h +++ b/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/kernel_forward.h @@ -174,10 +174,9 @@ struct AttentionKernel { scalar_t* key_ptr = nullptr; // [num_keys, num_heads, head_dim] scalar_t* value_ptr = nullptr; // [num_keys, num_heads, head_dim_value] scalar_t* attn_bias_ptr = nullptr; // [num_heads, num_queries, num_keys] - int32_t* seqstart_q_ptr = nullptr; - int32_t* seqstart_k_ptr = nullptr; - - int32_t* seqlen_k_ptr = nullptr; + const int32_t* seqstart_q_ptr = nullptr; + const int32_t* seqstart_k_ptr = nullptr; + const int32_t* seqlen_k_ptr = nullptr; uint32_t causal_diagonal_offset = 0; // Output tensors @@ -187,6 +186,8 @@ struct AttentionKernel { // [num_heads, num_queries] - can be null lse_scalar_t* logsumexp_ptr = nullptr; + int32_t window_size = -1; + // Scale accum_t scale = 0.0; @@ -651,6 +652,12 @@ struct AttentionKernel { XFORMERS_CHECK( p.custom_mask_type < NumCustomMaskTypes, "invalid value for `custom_mask_type`"); + if (p.window_size > 0) { + XFORMERS_CHECK( + p.custom_mask_type == CausalFromTopLeft || + p.custom_mask_type == CausalFromBottomRight, + "invalid value for custom_mask_type"); + } return true; } @@ -726,6 +733,13 @@ struct AttentionKernel { // Iterate through keys for (int32_t iter_key_start = 0; iter_key_start < p.num_keys; iter_key_start += kKeysPerBlock) { + if (p.window_size > 0) { + // don't compute anything if below attention band + if (iter_key_start + kKeysPerBlock < + static_cast(query_start + p.causal_diagonal_offset) - p.window_size) { + continue; + } + } int32_t problem_size_0_m = cutlass::fast_min((int32_t)kQueriesPerBlock, p.num_queries); int32_t problem_size_0_n = cutlass::fast_min( @@ -894,6 +908,38 @@ struct AttentionKernel { }, [&](int accum_m) {}); } + + // Mask out lower left corner of block if window_size > 0 + // only required if current block intersects with the lower left corner + // block starts at x_lowerleft = iter_key_start // y = query_start + + // kQueriesPerBlock first non masked value at this y is : x_first = + // query_start + kQueriesPerBlock - window_size mask if x_fist > + // x_lowerleft + + if (p.window_size > 0 && + (query_start + p.causal_diagonal_offset + + cutlass::fast_min( + static_cast(kQueriesPerBlock), static_cast(p.num_queries)) - + p.window_size >= + iter_key_start)) { + auto query_start = blockIdx.x * kQueriesPerBlock; + auto lane_offset = MM0::AccumLambdaIterator::get_lane_offset( + my_lane_id, my_warp_id, iteratorC_tile_offset); + int32_t first_col; + const int32_t offset = query_start + p.causal_diagonal_offset - + p.window_size - iter_key_start; + MM0::AccumLambdaIterator::iterateRows( + lane_offset, + [&](int accum_m) { first_col = accum_m + offset; }, + [&](int accum_m, int accum_n, int idx) { + if (accum_n <= first_col) { + accum[idx] = + -cutlass::platform::numeric_limits::infinity(); + } + }, + [&](int accum_m) {}); + } + // Update `mi` from accum stored in registers // Also does accum[i] <- exp(accum[i] - mi) iterative_softmax( @@ -1036,9 +1082,18 @@ struct AttentionKernel { } if (!kKeepOutputInRF) { + int first_key = 0; + if (p.window_size > 0) { + first_key = (cutlass::fast_max( + static_cast(query_start + p.causal_diagonal_offset) - + p.window_size + 1, + 0) / + kKeysPerBlock) * + kKeysPerBlock; + } MM1::Mma::drain_cp_asyncs(); DISPATCH_BOOL( - iter_key_start == 0, kIsFirst, ([&] { + iter_key_start == first_key, kIsFirst, ([&] { DISPATCH_BOOL( (iter_key_start + kKeysPerBlock) >= p.num_keys, kIsLast, diff --git a/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/memory_efficient_attention.h b/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/memory_efficient_attention.h index 9fe66c6fe992e..287413bf5acde 100644 --- a/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/memory_efficient_attention.h +++ b/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/memory_efficient_attention.h @@ -14,42 +14,39 @@ namespace cuda { constexpr int kEfficientAttentionMaxHeadSize = 1024; struct MemoryEfficientAttentionParams { - int32_t sm; - bool is_half; + int32_t sm = 50; + bool is_half = false; bool is_kv_bsnh = true; - int32_t batch_size; - int32_t num_heads; - int32_t sequence_length; - int32_t kv_sequence_length; - int32_t max_sequence_length; - int32_t qk_head_size; - int32_t v_head_size; - bool causal; - bool use_smooth_softmax; - - float scale; + int32_t batch_size = 0; + int32_t num_heads = 0; + int32_t sequence_length = 0; + int32_t kv_sequence_length = 0; + int32_t max_sequence_length = 0; + int32_t qk_head_size = 0; + int32_t v_head_size = 0; + int32_t local_window_size = -1; + bool causal = false; + bool use_smooth_softmax = false; + bool broadcast_attn_bias_dim_0 = false; + bool broadcast_attn_bias_dim_1 = false; + bool has_custom_right_padding = false; + float scale = 1.0f; float softcap = 0.0; - int32_t* seqstart_q_ptr; - int32_t* seqstart_k_ptr; - int32_t* seqlen_k_ptr; - - const void* query; // [B, S, N, H] - const void* key; // [B, L, N, H], where L is kv_sequence_length - const void* value; // [B, L, N, H_v] - const void* attn_bias; // [B or 1, N or 1, S, L] or null - bool broadcast_attn_bias_dim_0; - bool broadcast_attn_bias_dim_1; - - void* output; // [B, S, N, H_v] - void* workspace; // [B, S, N, H_v] when kNeedsOutputAccumulatorBuffer, nullptr otherwise - cudaStream_t stream; + cudaStream_t stream = nullptr; + const int32_t* seqstart_q_ptr = nullptr; // [B + 1], cumulated sequence lengths of queries + const int32_t* seqstart_k_ptr = nullptr; // [B + 1], cumulated sequence lengths of keys + const int32_t* seqlen_k_ptr = nullptr; // [B], sequence lengths of keys + const void* query = nullptr; // [B, S, N, H] + const void* key = nullptr; // [B, L, N, H], where L is kv_sequence_length + const void* value = nullptr; // [B, L, N, H_v] + const void* attn_bias = nullptr; // [B or 1, N or 1, S, L] or null + void* workspace = nullptr; // [B, S, N, H_v] when kNeedsOutputAccumulatorBuffer, nullptr otherwise + void* output = nullptr; // [B, S, N, H_v] static bool need_workspace(size_t v_head_size, bool is_float) { return (v_head_size > 128 && !is_float); } - - bool has_custom_right_padding = false; }; void run_memory_efficient_attention(const MemoryEfficientAttentionParams& params); diff --git a/onnxruntime/contrib_ops/cuda/bert/decoder_attention_impl.h b/onnxruntime/contrib_ops/cuda/bert/decoder_attention_impl.h index f9667a613e648..d5357a690ce47 100644 --- a/onnxruntime/contrib_ops/cuda/bert/decoder_attention_impl.h +++ b/onnxruntime/contrib_ops/cuda/bert/decoder_attention_impl.h @@ -4,6 +4,7 @@ #pragma once #include "contrib_ops/cuda/bert/attention_impl.h" +#include "contrib_ops/cuda/bert/attention_kv_cache.h" namespace onnxruntime { namespace contrib { diff --git a/onnxruntime/contrib_ops/cuda/bert/decoder_masked_multihead_attention.cc b/onnxruntime/contrib_ops/cuda/bert/decoder_masked_multihead_attention.cc index 350c4718c437e..bf94cca52a9e9 100644 --- a/onnxruntime/contrib_ops/cuda/bert/decoder_masked_multihead_attention.cc +++ b/onnxruntime/contrib_ops/cuda/bert/decoder_masked_multihead_attention.cc @@ -4,9 +4,13 @@ #include "core/providers/cuda/cuda_common.h" #include "core/providers/cuda/shared_inc/fpgeneric.h" #include "core/platform/env_var_utils.h" +#include "contrib_ops/cpu/bert/attention_parameters.h" #include "contrib_ops/cpu/bert/multihead_attention_helper.h" +#include "contrib_ops/cpu/utils/dump_tensor.h" +#include "contrib_ops/cuda/bert/attention_impl.h" #include "contrib_ops/cuda/bert/decoder_masked_multihead_attention.h" #include "contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_impl.h" +#include "contrib_ops/cuda/utils/dump_cuda_tensor.h" using namespace onnxruntime::cuda; using namespace ::onnxruntime::common; @@ -25,26 +29,29 @@ static constexpr int kPresentOutputIndex = 1; static constexpr int kQKOutputIndex = 3; static constexpr int kBiasIndex = 10; -#define REGISTER_KERNEL_TYPED(T1, T2) \ +#define REGISTER_KERNEL_TYPED(T, QK) \ ONNX_OPERATOR_TYPED_KERNEL_EX( \ DecoderMaskedMultiHeadAttention, \ kMSDomain, \ 1, \ - T1, \ + T##_##QK, \ kCudaExecutionProvider, \ (*KernelDefBuilder::Create()) \ .MayInplace(kPastInputIndex, kPresentOutputIndex) \ .MayInplace(kPastInputIndex + 1, kPresentOutputIndex + 1) \ - .TypeConstraint("T", DataTypeImpl::GetTensorType()) \ + .TypeConstraint("T", DataTypeImpl::GetTensorType()) \ + .TypeConstraint("QK", DataTypeImpl::GetTensorType()) \ .InputMemoryType(OrtMemTypeCPUInput, kPastSequenceLengthInputIndex) \ .InputMemoryType(OrtMemTypeCPUInput, kBeamWidthInputIndex), \ - DecoderMaskedMultiHeadAttention); + DecoderMaskedMultiHeadAttention); REGISTER_KERNEL_TYPED(float, float) -REGISTER_KERNEL_TYPED(MLFloat16, uint16_t) +REGISTER_KERNEL_TYPED(float, MLFloat16) +REGISTER_KERNEL_TYPED(MLFloat16, float) +REGISTER_KERNEL_TYPED(MLFloat16, MLFloat16) -template -DecoderMaskedMultiHeadAttention::DecoderMaskedMultiHeadAttention(const OpKernelInfo& info) : CudaKernel(info) { +template +DecoderMaskedMultiHeadAttention::DecoderMaskedMultiHeadAttention(const OpKernelInfo& info) : CudaKernel(info) { int64_t num_heads = 0; ORT_ENFORCE(info.GetAttr("num_heads", &num_heads).IsOK() && num_heads > 0); num_heads_ = static_cast(num_heads); @@ -54,8 +61,8 @@ DecoderMaskedMultiHeadAttention::DecoderMaskedMultiHeadAttention(const O output_qk_ = info.GetAttrOrDefault("output_qk", 0LL); } -template -Status DecoderMaskedMultiHeadAttention::ComputeInternal(OpKernelContext* context) const { +template +Status DecoderMaskedMultiHeadAttention::ComputeInternal(OpKernelContext* context) const { const Tensor* query = context->Input(0); const Tensor* key = context->Input(1); const Tensor* value = context->Input(2); @@ -69,7 +76,7 @@ Status DecoderMaskedMultiHeadAttention::ComputeInternal(OpKernelContext* const Tensor* bias = context->Input(kBiasIndex); auto& device_prop = GetDeviceProp(); - DecoderMaskedMultiHeadAttentionParams parameters; + DecoderMaskedMultiHeadAttentionParameters parameters; parameters.kv_data_in_flight = ParseEnvironmentVariableWithDefault( attention::kDecoderMaskedAttentionLoadKVDataInFlight, false); @@ -83,6 +90,7 @@ Status DecoderMaskedMultiHeadAttention::ComputeInternal(OpKernelContext* attention_bias, past_key, past_value, + cache_indir, past_seq_len, ¶meters, num_heads_, @@ -93,11 +101,24 @@ Status DecoderMaskedMultiHeadAttention::ComputeInternal(OpKernelContext* kDecoderMaskedMultiHeadAttention, device_prop.maxThreadsPerBlock)); + DUMP_STRING_INIT(); + DUMP_STRING("Batch size = ", parameters.batch_size); + DUMP_STRING("Sequence length = ", parameters.sequence_length); + DUMP_STRING("Past sequence length = ", parameters.past_sequence_length); + DUMP_STRING("KV sequence length = ", parameters.kv_sequence_length); + DUMP_STRING("Total sequence length = ", parameters.total_sequence_length); + DUMP_STRING("Max sequence length = ", parameters.max_sequence_length); + DUMP_STRING("Hidden size = ", parameters.hidden_size); + DUMP_STRING("Head size = ", parameters.head_size); + DUMP_STRING("Num heads = ", parameters.num_heads); + DUMP_STRING("Buffer sharing = ", (parameters.past_present_share_buffer == true)); + DUMP_STRING("QKV format = ", parameters.qkv_format); + if (bias) { - const T1* bias_data = bias->Data(); - parameters.q_bias = const_cast(bias_data); - parameters.k_bias = const_cast(bias_data + parameters.hidden_size); - parameters.v_bias = const_cast(bias_data + 2LL * parameters.hidden_size); + const T* bias_data = bias->Data(); + parameters.q_bias = const_cast(bias_data); + parameters.k_bias = const_cast(bias_data + parameters.hidden_size); + parameters.v_bias = const_cast(bias_data + 2LL * parameters.hidden_size); } int batch_size = parameters.batch_size; @@ -125,10 +146,7 @@ Status DecoderMaskedMultiHeadAttention::ComputeInternal(OpKernelContext* output_shape[2] = static_cast(parameters.v_hidden_size); Tensor* output = context->Output(0, output_shape); - std::vector present_dims{ - parameters.batch_size, parameters.num_heads, - past_present_share_buffer_ ? parameters.max_sequence_length : parameters.total_sequence_length, - parameters.head_size}; + std::vector present_dims{parameters.batch_size, parameters.num_heads, parameters.max_sequence_length, parameters.head_size}; TensorShape present_shape(present_dims); Tensor* present_key = context->Output(kPresentOutputIndex, present_shape); Tensor* present_value = context->Output(kPresentOutputIndex + 1, present_shape); @@ -139,11 +157,11 @@ Status DecoderMaskedMultiHeadAttention::ComputeInternal(OpKernelContext* parameters.is_mha = true; // Update the q buffers - parameters.q = const_cast(query->Data()); + parameters.q = const_cast(query->Data()); // Update the attention bias for self attention if (attention_bias != nullptr) { - parameters.attention_bias = const_cast(attention_bias->Data()); + parameters.attention_bias = const_cast(attention_bias->Data()); } // Decoder cross-attention @@ -157,8 +175,8 @@ Status DecoderMaskedMultiHeadAttention::ComputeInternal(OpKernelContext* parameters.total_sequence_length = parameters.kv_sequence_length; parameters.max_sequence_length = parameters.kv_sequence_length; // parameters.k and parameters.v are nullptr - parameters.k_cache = const_cast(key->Data()); - parameters.v_cache = const_cast(value->Data()); + parameters.k_cache = const_cast(key->Data()); + parameters.v_cache = const_cast(value->Data()); parameters.k_bias = nullptr; parameters.v_bias = nullptr; @@ -167,10 +185,10 @@ Status DecoderMaskedMultiHeadAttention::ComputeInternal(OpKernelContext* ORT_ENFORCE(past_present_share_buffer_); ORT_ENFORCE(past_key != nullptr && past_value != nullptr); - auto* present_key_data = present_key->MutableData(); - auto* present_value_data = present_value->MutableData(); - auto* past_key_data = past_key->Data(); - auto* past_value_data = past_value->Data(); + auto* present_key_data = present_key->MutableData(); + auto* present_value_data = present_value->MutableData(); + auto* past_key_data = past_key->Data(); + auto* past_value_data = past_value->Data(); // No production use-case will incur this copy cost as the implementation of // GreedySearch/BeamSearch is written in such a way that the past and present buffers @@ -192,11 +210,11 @@ Status DecoderMaskedMultiHeadAttention::ComputeInternal(OpKernelContext* parameters.is_packed_qkv = is_packed_qkv; parameters.k = is_packed_qkv - ? const_cast(query->Data() + parameters.hidden_size) - : const_cast(key->Data()); + ? const_cast(query->Data() + parameters.hidden_size) + : const_cast(key->Data()); parameters.v = is_packed_qkv - ? const_cast(query->Data() + 2 * static_cast(parameters.hidden_size)) - : const_cast(value->Data()); + ? const_cast(query->Data() + 2 * static_cast(parameters.hidden_size)) + : const_cast(value->Data()); parameters.k_cache = present_key_data; parameters.v_cache = present_value_data; } @@ -205,7 +223,7 @@ Status DecoderMaskedMultiHeadAttention::ComputeInternal(OpKernelContext* int64_t qk_dims[] = {parameters.batch_size, parameters.num_heads, 1, parameters.total_sequence_length}; TensorShape qk_shape(&qk_dims[0], sizeof(qk_dims) / sizeof(qk_dims[0])); cross_qk = context->Output(kQKOutputIndex, qk_shape); - parameters.out_qk = cross_qk->MutableData(); + parameters.out_qk = cross_qk->MutableData(); } parameters.out = output->MutableDataRaw(); @@ -237,26 +255,19 @@ Status DecoderMaskedMultiHeadAttention::ComputeInternal(OpKernelContext* parameters.cache_indir = cache_indir->Data(); } - switch (parameters.head_size) { - case 32: - mmha_launch_kernel(parameters, cuda_stream); - break; - - case 64: - mmha_launch_kernel(parameters, cuda_stream); - break; - - case 128: - mmha_launch_kernel(parameters, cuda_stream); - break; - - default: - return ORT_MAKE_STATUS(ONNXRUNTIME, NOT_IMPLEMENTED, - "Unsupported head size in DecoderMaskedMultiHeadAttention. " - "Got head size: ", - parameters.head_size); + // DecoderMaskedMultiHeadAttention(T, QK) is defined for: + // T = float, QK = float + // T = float, QK = half + // T = uint16_t, QK = float + // T = uint16_t, QK = half + typedef typename ToCudaType::MappedType CudaQK; + if (std::is_same::value) { + return LaunchDecoderMaskedMultiHeadAttention(parameters, cuda_stream, parameters.head_size); + } + if (std::is_same::value) { + return LaunchDecoderMaskedMultiHeadAttention(parameters, cuda_stream, parameters.head_size); } - return Status::OK(); + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "DecoderMaskedMultiHeadAttention is only implemented for float32 and float16."); } } // namespace cuda diff --git a/onnxruntime/contrib_ops/cuda/bert/decoder_masked_self_attention.cc b/onnxruntime/contrib_ops/cuda/bert/decoder_masked_self_attention.cc index e7d117686a538..a15b59d0c018a 100644 --- a/onnxruntime/contrib_ops/cuda/bert/decoder_masked_self_attention.cc +++ b/onnxruntime/contrib_ops/cuda/bert/decoder_masked_self_attention.cc @@ -4,6 +4,8 @@ #include "core/providers/cuda/cuda_common.h" #include "core/providers/cuda/shared_inc/fpgeneric.h" #include "core/platform/env_var_utils.h" +#include "contrib_ops/cpu/bert/attention_parameters.h" +#include "contrib_ops/cuda/bert/attention_impl.h" #include "contrib_ops/cuda/bert/decoder_masked_self_attention.h" #include "contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_impl.h" @@ -51,7 +53,7 @@ Status DecoderMaskedSelfAttention::ComputeInternal(OpKernelContext* cont const Tensor* cache_indir = context->Input(kCacheIndirectionInputIndex); auto& device_prop = GetDeviceProp(); - DecoderMaskedMultiHeadAttentionParams parameters; + DecoderMaskedMultiHeadAttentionParameters parameters; parameters.kv_data_in_flight = ParseEnvironmentVariableWithDefault( attention::kDecoderMaskedAttentionLoadKVDataInFlight, false); @@ -197,26 +199,7 @@ Status DecoderMaskedSelfAttention::ComputeInternal(OpKernelContext* cont parameters.t_step = parameters.past_sequence_length; } - switch (parameters.head_size) { - case 32: - mmha_launch_kernel(parameters, cuda_stream); - break; - - case 64: - mmha_launch_kernel(parameters, cuda_stream); - break; - - case 128: - mmha_launch_kernel(parameters, cuda_stream); - break; - - default: - return ORT_MAKE_STATUS(ONNXRUNTIME, NOT_IMPLEMENTED, - "Unsupported head size in DecoderMaskedSelfAttention. " - "Got head size: ", - parameters.head_size); - } - return Status::OK(); + return LaunchDecoderMaskedMultiHeadAttention(parameters, cuda_stream, parameters.head_size); } } // namespace cuda diff --git a/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_128.cu b/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_128.cu index 3582758d1daba..0f2db956e55db 100644 --- a/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_128.cu +++ b/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_128.cu @@ -29,35 +29,37 @@ namespace cuda { using namespace decoder_masked_self_attention_details; #define MMHA_LAUNCH_KERNEL( \ - T, head_size, THDS_PER_KEY, THDS_PER_VALUE, THDS_PER_BLOCK) \ + T, QK, head_size, THDS_PER_KEY, THDS_PER_VALUE, THDS_PER_BLOCK) \ size_t dynamic_block_memory = CalcDynamicBlockMemory(params, THDS_PER_VALUE, THDS_PER_BLOCK); \ dim3 grid(params.num_heads, params.batch_size); \ masked_multihead_attention_kernel \ <<>>(params) -template -void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParams& params, cudaStream_t stream) { +template +void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParameters& params, cudaStream_t stream) { constexpr int THREADS_PER_VALUE = ThreadsPerValue::value; int total_sequence_length = params.total_sequence_length; if (total_sequence_length < 32) { - MMHA_LAUNCH_KERNEL(T, head_size, 4, THREADS_PER_VALUE, 64); + MMHA_LAUNCH_KERNEL(T, QK, head_size, 4, THREADS_PER_VALUE, 64); } else if (total_sequence_length < 2048) { - MMHA_LAUNCH_KERNEL(T, head_size, 2, THREADS_PER_VALUE, 128); + MMHA_LAUNCH_KERNEL(T, QK, head_size, 2, THREADS_PER_VALUE, 128); } else { - MMHA_LAUNCH_KERNEL(T, head_size, 1, THREADS_PER_VALUE, 256); + MMHA_LAUNCH_KERNEL(T, QK, head_size, 1, THREADS_PER_VALUE, 256); } } // Instantiate templates -template void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParams& params, cudaStream_t stream); - -template void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParams& params, cudaStream_t stream); +template void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParameters& params, cudaStream_t stream); +template void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParameters& params, cudaStream_t stream); +template void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParameters& params, cudaStream_t stream); +template void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParameters& params, cudaStream_t stream); } // namespace cuda } // namespace contrib -} // namespace onnxruntime \ No newline at end of file +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_32.cu b/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_32.cu index 3d295116252f6..d878291cabca0 100644 --- a/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_32.cu +++ b/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_32.cu @@ -29,35 +29,37 @@ namespace cuda { using namespace decoder_masked_self_attention_details; #define MMHA_LAUNCH_KERNEL( \ - T, head_size, THDS_PER_KEY, THDS_PER_VALUE, THDS_PER_BLOCK) \ + T, QK, head_size, THDS_PER_KEY, THDS_PER_VALUE, THDS_PER_BLOCK) \ size_t dynamic_block_memory = CalcDynamicBlockMemory(params, THDS_PER_VALUE, THDS_PER_BLOCK); \ dim3 grid(params.num_heads, params.batch_size); \ masked_multihead_attention_kernel \ <<>>(params) -template -void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParams& params, cudaStream_t stream) { +template +void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParameters& params, cudaStream_t stream) { constexpr int THREADS_PER_VALUE = ThreadsPerValue::value; int total_sequence_length = params.total_sequence_length; if (total_sequence_length < 32) { - MMHA_LAUNCH_KERNEL(T, head_size, 4, THREADS_PER_VALUE, 64); + MMHA_LAUNCH_KERNEL(T, QK, head_size, 4, THREADS_PER_VALUE, 64); } else if (total_sequence_length < 2048) { - MMHA_LAUNCH_KERNEL(T, head_size, 2, THREADS_PER_VALUE, 128); + MMHA_LAUNCH_KERNEL(T, QK, head_size, 2, THREADS_PER_VALUE, 128); } else { - MMHA_LAUNCH_KERNEL(T, head_size, 1, THREADS_PER_VALUE, 256); + MMHA_LAUNCH_KERNEL(T, QK, head_size, 1, THREADS_PER_VALUE, 256); } } // Instantiate templates -template void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParams& params, cudaStream_t stream); - -template void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParams& params, cudaStream_t stream); +template void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParameters& params, cudaStream_t stream); +template void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParameters& params, cudaStream_t stream); +template void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParameters& params, cudaStream_t stream); +template void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParameters& params, cudaStream_t stream); } // namespace cuda } // namespace contrib -} // namespace onnxruntime \ No newline at end of file +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_64.cu b/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_64.cu index e5f57fac73cf2..b547ad67a61a5 100644 --- a/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_64.cu +++ b/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_64.cu @@ -29,35 +29,37 @@ namespace cuda { using namespace decoder_masked_self_attention_details; #define MMHA_LAUNCH_KERNEL( \ - T, head_size, THDS_PER_KEY, THDS_PER_VALUE, THDS_PER_BLOCK) \ + T, QK, head_size, THDS_PER_KEY, THDS_PER_VALUE, THDS_PER_BLOCK) \ size_t dynamic_block_memory = CalcDynamicBlockMemory(params, THDS_PER_VALUE, THDS_PER_BLOCK); \ dim3 grid(params.num_heads, params.batch_size); \ masked_multihead_attention_kernel \ <<>>(params) -template -void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParams& params, cudaStream_t stream) { +template +void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParameters& params, cudaStream_t stream) { constexpr int THREADS_PER_VALUE = ThreadsPerValue::value; int total_sequence_length = params.total_sequence_length; if (total_sequence_length < 32) { - MMHA_LAUNCH_KERNEL(T, head_size, 4, THREADS_PER_VALUE, 64); + MMHA_LAUNCH_KERNEL(T, QK, head_size, 4, THREADS_PER_VALUE, 64); } else if (total_sequence_length < 2048) { - MMHA_LAUNCH_KERNEL(T, head_size, 2, THREADS_PER_VALUE, 128); + MMHA_LAUNCH_KERNEL(T, QK, head_size, 2, THREADS_PER_VALUE, 128); } else { - MMHA_LAUNCH_KERNEL(T, head_size, 1, THREADS_PER_VALUE, 256); + MMHA_LAUNCH_KERNEL(T, QK, head_size, 1, THREADS_PER_VALUE, 256); } } // Instantiate templates -template void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParams& params, cudaStream_t stream); - -template void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParams& params, cudaStream_t stream); +template void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParameters& params, cudaStream_t stream); +template void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParameters& params, cudaStream_t stream); +template void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParameters& params, cudaStream_t stream); +template void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParameters& params, cudaStream_t stream); } // namespace cuda } // namespace contrib -} // namespace onnxruntime \ No newline at end of file +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_impl.cu b/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_impl.cu index e4c1659c0fb2c..75ea7454791b6 100644 --- a/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_impl.cu +++ b/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_impl.cu @@ -39,6 +39,8 @@ using namespace decoder_masked_self_attention_details; template < // The type of the inputs. Supported types: float and half. typename T, + // The type of the QK output. Supported types: float and half. + typename QK, // The hidden dimension per head. int head_size, // The number of threads per key. @@ -47,7 +49,7 @@ template < int THREADS_PER_VALUE, // The number of threads in a threadblock. int THREADS_PER_BLOCK> -__global__ void masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParams params) { +__global__ void masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params) { // This kernel contains some code that cannot be compiled on CUDA ARCH 5.3 or lower #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 530 (void)(params); @@ -537,9 +539,9 @@ __global__ void masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentio if (params.out_qk != nullptr) { // store cross qk before softmax, out_qk has shape [B(batchxbeam), #Head, 1, total_sequence_length] - float* target = (reinterpret_cast(params.out_qk)) + (static_cast(bhi) * (sum_tlength + 1)); + QK* target = (reinterpret_cast(params.out_qk)) + (static_cast(bhi) * (sum_tlength + 1)); for (int ti = tidx; ti <= sum_tlength; ti += THREADS_PER_BLOCK) { - target[ti] = (float)(qk_smem[ti]); + target[ti] = static_cast(qk_smem[ti]); } } @@ -739,46 +741,58 @@ __global__ void masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentio // Template instantiation(s) // fp32 + head size = 32 -template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParams params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); -template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParams params); - -template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParams params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); // fp16 + head size = 32 -template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParams params); - -template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParams params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); -template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParams params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); // fp32 + head size = 64 -template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParams params); - -template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParams params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); -template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParams params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); // fp16 + head size = 64 -template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParams params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); -template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParams params); - -template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParams params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); // fp32 + head size = 128 -template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParams params); - -template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParams params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); -template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParams params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); // fp16 + head size = 128 -template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParams params); - -template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParams params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); -template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParams params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); +template void __global__ masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); } // namespace cuda } // namespace contrib diff --git a/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_impl.h b/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_impl.h index 0e1c9ce7b108e..4dbf7d932b389 100644 --- a/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_impl.h +++ b/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_impl.h @@ -5,6 +5,7 @@ #include "core/providers/cuda/cuda_common.h" #include "contrib_ops/cpu/bert/attention_common.h" +#include "contrib_ops/cpu/bert/attention_parameters.h" namespace onnxruntime { namespace contrib { @@ -13,6 +14,8 @@ namespace cuda { template < // The type of the inputs. Supported types: float and half. typename T, + // The type of the QK output. Supported types: float and half. + typename QK, // The hidden dimension per head. int head_size, // The number of threads per key. @@ -21,10 +24,15 @@ template < int THREADS_PER_VALUE, // The number of threads in a threadblock. int THREADS_PER_BLOCK> -__global__ void masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParams params); +__global__ void masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentionParameters params); -template -void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParams& params, cudaStream_t stream); +template +void mmha_launch_kernel(const DecoderMaskedMultiHeadAttentionParameters& params, cudaStream_t stream); + +inline bool has_decoder_masked_multihead_attention(int sm, int head_size) { + // This kernel contains some code that cannot be compiled on CUDA ARCH 5.3 or lower + return (sm >= 53) && (head_size == 32 || head_size == 64 || head_size == 128); +} } // namespace cuda diff --git a/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_impl_utils.h b/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_impl_utils.h index 6b012432cd0f5..08e4293528d5a 100644 --- a/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_impl_utils.h +++ b/onnxruntime/contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_impl_utils.h @@ -24,6 +24,7 @@ #pragma once +#include "contrib_ops/cpu/bert/attention_parameters.h" #include "contrib_ops/cuda/bert/utils.cuh" using namespace onnxruntime::cuda; @@ -140,7 +141,7 @@ struct ThreadsPerValue { //------------------------------------------------------------ template -inline size_t CalcDynamicBlockMemory(const DecoderMaskedMultiHeadAttentionParams& params, +inline size_t CalcDynamicBlockMemory(const DecoderMaskedMultiHeadAttentionParameters& params, int threads_per_value, int threads_per_block) { // The amount of shared memory needed to store the Q*K^T values in float. diff --git a/onnxruntime/contrib_ops/cuda/bert/group_query_attention.cc b/onnxruntime/contrib_ops/cuda/bert/group_query_attention.cc index 6eff584cec5da..9f1bc46ee297d 100644 --- a/onnxruntime/contrib_ops/cuda/bert/group_query_attention.cc +++ b/onnxruntime/contrib_ops/cuda/bert/group_query_attention.cc @@ -156,13 +156,8 @@ Status GroupQueryAttention::ComputeInternal(OpKernelContext* context) const { bool use_memory_efficient_attention = !use_flash_attention && !disable_memory_efficient_attention_ && - local_window_size_ == -1 && - (sizeof(T) == 2 || parameters.sequence_length >= this->kernel_options_->MinSeqLenForEfficientAttentionFp32()) && has_memory_efficient_attention(sm, sizeof(T) == 2, parameters.head_size, parameters.head_size); - if (!use_flash_attention && !use_memory_efficient_attention && local_window_size_ != -1) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "Local attention UNSUPPORTED for sm < 80 on CUDA."); - } + // allocate buffers size_t kv_buffer_bytes = 0; // need a buffer if we must ungroup kv @@ -262,17 +257,6 @@ Status GroupQueryAttention::ComputeInternal(OpKernelContext* context) const { if (fmha_buffer != nullptr) { data.fmha_buffer = reinterpret_cast(fmha_buffer.get()); } - if (k_buffer != nullptr) { - data.k = reinterpret_cast(k_buffer.get()); - data.v = reinterpret_cast(v_buffer.get()); - } - if (k_buffer != nullptr) { - data.k = reinterpret_cast(k_buffer.get()); - data.v = reinterpret_cast(v_buffer.get()); - } - if (fmha_buffer != nullptr) { - data.fmha_buffer = reinterpret_cast(fmha_buffer.get()); - } if (unpacked_qkv_buffer != nullptr) { data.unpacked_qkv_buffer = reinterpret_cast(unpacked_qkv_buffer.get()); } diff --git a/onnxruntime/contrib_ops/cuda/bert/group_query_attention_impl.cu b/onnxruntime/contrib_ops/cuda/bert/group_query_attention_impl.cu index 8bf9848245ec7..2d1b49033003d 100644 --- a/onnxruntime/contrib_ops/cuda/bert/group_query_attention_impl.cu +++ b/onnxruntime/contrib_ops/cuda/bert/group_query_attention_impl.cu @@ -47,9 +47,6 @@ limitations under the License. using namespace onnxruntime::cuda; -// Macro to help compute index of flatten 4D matrix, note that dim1 is not used so it is excluded. -#define INDEX_4D(dim2, dim3, dim4, i, j, k, l) ((i) * (dim2) * (dim3) * (dim4) + (j) * (dim3) * (dim4) + (k) * (dim4) + (l)) - namespace onnxruntime { namespace contrib { namespace cuda { @@ -62,101 +59,6 @@ __global__ void repeat_seqlen(int32_t* seqlens_k, int32_t seqlen, int batch_size if (id < batch_size) seqlens_k[id] = seqlen; } -// Kernel to append new and past kv in either BSNH or BNSH format -// Adapted from ConcatTensorToTensor kernel in attention_kv_cache.cu file -template -__global__ void ConcatNewToPastKV(const int new_seqlen, - const int past_buffer_seqlen, - const T* past_kv, - const T* new_kv, - T* present_kv, - const int* seqlens_k, - const bool past_only, - // const int* seqlens_q, - const bool is_bsnh) { // refers to past; otherwise bnsh - const int h = threadIdx.x; - const int n = threadIdx.y; - const int s = blockIdx.x; - const int b = blockIdx.y; - - const int present_buffer_seqlen = gridDim.x; - const int num_heads = blockDim.y; - const int H = blockDim.x; - - const int present_batch_stride = present_buffer_seqlen * num_heads * H; - const int row_stride = is_bsnh ? num_heads * H : H; - const int present_head_stride = is_bsnh ? H : present_buffer_seqlen * H; - - // past_kv: BPNH or BNPH - // new_kv: BLNH - // present_kv: BTNH or BNTH, where T = P + L - - // prompt, token, and interactive decoding cases - const int past_seqlen = seqlens_k == nullptr ? 0 : seqlens_k[b] + 1 - new_seqlen; - - int out_offset = b * present_batch_stride + s * row_stride + n * present_head_stride + h; - if (s < past_seqlen) { - const int past_batch_stride = past_buffer_seqlen * num_heads * H; - const int past_head_stride = is_bsnh ? H : past_buffer_seqlen * H; - const int in_offset = b * past_batch_stride + s * row_stride + n * past_head_stride + h; - present_kv[out_offset] = past_kv[in_offset]; - } else if (!past_only && s < past_seqlen + new_seqlen) { - // Note: new KV always BSNH - const int new_batch_stride = new_seqlen * num_heads * H; - const int new_row_stride = num_heads * H; - const int new_head_stride = H; - const int in_offset = b * new_batch_stride + (s - past_seqlen) * new_row_stride + n * new_head_stride + h; - present_kv[out_offset] = new_kv[in_offset]; - } -} - -// Use when (H*)*num_heads > 1024 -template -__global__ void ConcatNewToPastKVLarge(const int new_seqlen, - const int past_buffer_seqlen, - const int H, - const int num_heads, - const T* past_kv, - const T* new_kv, - T* present_kv, - const int* seqlens_k, - const bool past_only, - const bool is_bsnh) { - int i = threadIdx.x + (blockDim.x * blockIdx.x); - if (i < H * num_heads) { - const int h = i % H; - const int n = i / H; - const int s = blockIdx.y; - const int b = blockIdx.z; - const int present_buffer_seqlen = gridDim.y; - - const int present_batch_stride = present_buffer_seqlen * num_heads * H; - const int row_stride = is_bsnh ? num_heads * H : H; - const int present_head_stride = is_bsnh ? H : present_buffer_seqlen * H; - - // past_kv: BPNH or BNPH - // new_kv: BLNH - // present_kv: BTNH or BNTH, where T = P + L - - // prompt, token, and interactive decoding cases - const int past_seqlen = seqlens_k == nullptr ? 0 : seqlens_k[b] + 1 - new_seqlen; - - int out_offset = b * present_batch_stride + s * row_stride + n * present_head_stride + h; - if (s < past_seqlen) { - const int past_batch_stride = past_buffer_seqlen * num_heads * H; - const int past_head_stride = is_bsnh ? H : past_buffer_seqlen * H; - const int in_offset = b * past_batch_stride + s * row_stride + n * past_head_stride + h; - present_kv[out_offset] = past_kv[in_offset]; - } else if (!past_only && s < past_seqlen + new_seqlen) { - const int new_batch_stride = new_seqlen * num_heads * H; - const int new_row_stride = num_heads * H; - const int new_head_stride = H; - const int in_offset = b * new_batch_stride + (s - past_seqlen) * new_row_stride + n * new_head_stride + h; - present_kv[out_offset] = new_kv[in_offset]; - } - } -} - // Concat new to past in present. Supports past BSNH or past BNSH template Status LaunchConcatNewToPastKV(contrib::GroupQueryAttentionParameters& parameters, @@ -174,185 +76,26 @@ Status LaunchConcatNewToPastKV(contrib::GroupQueryAttentionParameters& parameter const int head_size = parameters.head_size; const int* seqlens_k = parameters.is_first_prompt ? nullptr : reinterpret_cast(data.seqlens_k); AttentionQkvFormat past_kv_format = parameters.past_kv_format; - assert(past_kv_format == AttentionQkvFormat::Q_K_V_BSNH || past_kv_format == AttentionQkvFormat::Q_K_V_BNSH); - const int H = head_size / 4; // divide by 4 so kernel can operate on 4 float16 elements at a time. - if (H * kv_num_heads <= max_threads_per_block) { - const dim3 grid(present_sequence_length, batch_size, 1); - const dim3 block(H, kv_num_heads, 1); - ConcatNewToPastKV<<>>(kv_sequence_length, - past_sequence_length, - reinterpret_cast(data.past_key), - reinterpret_cast(new_key), - reinterpret_cast(data.present_key), - seqlens_k, - past_only, - past_kv_format == AttentionQkvFormat::Q_K_V_BSNH); - ConcatNewToPastKV<<>>(kv_sequence_length, - past_sequence_length, - reinterpret_cast(data.past_value), - reinterpret_cast(new_value), - reinterpret_cast(data.present_value), - seqlens_k, - past_only, - past_kv_format == AttentionQkvFormat::Q_K_V_BSNH); - } else { - int steps = (H * kv_num_heads + 255) / 256; - const dim3 grid(steps, present_sequence_length, batch_size); - const dim3 block(256, 1, 1); - ConcatNewToPastKVLarge<<>>(kv_sequence_length, - past_sequence_length, - H, - kv_num_heads, - reinterpret_cast(data.past_key), - reinterpret_cast(new_key), - reinterpret_cast(data.present_key), - seqlens_k, - past_only, - past_kv_format == AttentionQkvFormat::Q_K_V_BSNH); - ConcatNewToPastKVLarge<<>>(kv_sequence_length, - past_sequence_length, - H, - kv_num_heads, - reinterpret_cast(data.past_value), - reinterpret_cast(new_value), - reinterpret_cast(data.present_value), - seqlens_k, - past_only, - past_kv_format == AttentionQkvFormat::Q_K_V_BSNH); - } - return CUDA_CALL(cudaGetLastError()); -} - -// Kernel to append new kv to kv buffer in place -template -__global__ void ConcatKVInPlace(const int max_seqlen, - T* kv_buff, - const T* new_kv, - const int* seqlens_k, - const int* total_seqlens_k, - const bool is_past_kv_bnsh_format, - const bool is_new_kv_bnsh_format) { - const int h = threadIdx.x; - const int n = threadIdx.y; - const int s = blockIdx.x; - const int b = blockIdx.y; - - const int new_seqlen = gridDim.x; - const int kv_num_heads = blockDim.y; - const int H = blockDim.x; - - const int past_seq_len = (total_seqlens_k != nullptr) - ? (total_seqlens_k[b] - new_seqlen) - : (seqlens_k == nullptr ? 0 : (seqlens_k[b] + 1 - new_seqlen)); - - int out_offset = is_past_kv_bnsh_format - ? INDEX_4D(kv_num_heads, max_seqlen, H, b, n, s + past_seq_len, h) - : INDEX_4D(max_seqlen, kv_num_heads, H, b, s + past_seq_len, n, h); - - int in_offset = is_new_kv_bnsh_format - ? INDEX_4D(kv_num_heads, new_seqlen, H, b, n, s, h) - : INDEX_4D(new_seqlen, kv_num_heads, H, b, s, n, h); - - kv_buff[out_offset] = new_kv[in_offset]; -} - -template -__global__ void ConcatKVInPlaceLarge(const int max_seqlen, - const int H, - const int kv_num_heads, - T* kv_buff, - const T* new_kv, - const int* seqlens_k, - const int* total_seqlens_k, - const bool is_past_kv_bnsh_format, - const bool is_new_kv_bnsh_format) { // refers to kv buff; otherwise bnsh - int i = threadIdx.x + (blockDim.x * blockIdx.x); - if (i < H * kv_num_heads) { - const int h = i % H; - const int n = i / H; - const int s = blockIdx.y; - const int b = blockIdx.z; - const int new_seqlen = gridDim.y; - - const int past_seq_len = (total_seqlens_k != nullptr) - ? (total_seqlens_k[b] - new_seqlen) - : (seqlens_k == nullptr ? 0 : (seqlens_k[b] + 1 - new_seqlen)); - - int out_offset = is_past_kv_bnsh_format - ? INDEX_4D(kv_num_heads, max_seqlen, H, b, n, s + past_seq_len, h) - : INDEX_4D(max_seqlen, kv_num_heads, H, b, s + past_seq_len, n, h); - - int in_offset = is_new_kv_bnsh_format - ? INDEX_4D(kv_num_heads, new_seqlen, H, b, n, s, h) - : INDEX_4D(new_seqlen, kv_num_heads, H, b, s, n, h); - - kv_buff[out_offset] = new_kv[in_offset]; - } -} - -// Concat new to kv buffer in place -template -Status LaunchConcatKVInPlace(int batch_size, - int kv_num_heads, - int head_size, - int max_sequence_length, - const int* seqlens_k, - const int* total_seqlens_k, - int new_seq_len, - const T* new_key, - const T* new_value, - T* present_key, - T* present_value, - const bool is_past_kv_bnsh_format, - const bool is_new_kv_bnsh_format, - cudaStream_t stream, - const int max_threads_per_block) { - static_assert(sizeof(T) == 2); - assert(head_size % 4 == 0); + const bool is_bsnh = past_kv_format == AttentionQkvFormat::Q_K_V_BSNH; - const int H = head_size / 4; - if (H * kv_num_heads <= max_threads_per_block) { - const dim3 grid(new_seq_len, batch_size, 1); - const dim3 block(H, kv_num_heads, 1); - ConcatKVInPlace<<>>(max_sequence_length, - reinterpret_cast(present_key), - reinterpret_cast(new_key), - seqlens_k, - total_seqlens_k, - is_past_kv_bnsh_format, - is_new_kv_bnsh_format); - ConcatKVInPlace<<>>(max_sequence_length, - reinterpret_cast(present_value), - reinterpret_cast(new_value), - seqlens_k, - total_seqlens_k, - is_past_kv_bnsh_format, - is_new_kv_bnsh_format); - } else { - int steps = int(ceil(float(H * kv_num_heads) / 256.0)); - const dim3 grid(steps, new_seq_len, batch_size); - const dim3 block(256, 1, 1); - ConcatKVInPlaceLarge<<>>(max_sequence_length, - H, - kv_num_heads, - reinterpret_cast(present_key), - reinterpret_cast(new_key), - seqlens_k, - total_seqlens_k, - is_past_kv_bnsh_format, - is_new_kv_bnsh_format); - ConcatKVInPlaceLarge<<>>(max_sequence_length, - H, - kv_num_heads, - reinterpret_cast(present_value), - reinterpret_cast(new_value), - seqlens_k, - total_seqlens_k, - is_past_kv_bnsh_format, - is_new_kv_bnsh_format); - } - return CUDA_CALL(cudaGetLastError()); + return LaunchConcatNewToPastKV(batch_size, + kv_num_heads, + head_size, + kv_sequence_length, + past_sequence_length, + present_sequence_length, + is_bsnh, + seqlens_k, + data.past_key, + data.past_value, + reinterpret_cast(new_key), + reinterpret_cast(new_value), + data.present_key, + data.present_value, + stream, + max_threads_per_block, + past_only); } // Concat new to kv buffer in place @@ -892,6 +635,7 @@ Status EfficientAttention( p.stream = stream; p.has_custom_right_padding = true; p.use_smooth_softmax = parameters.use_smooth_softmax; + p.local_window_size = parameters.local_window_size; run_memory_efficient_attention(p); DUMP_TENSOR("efficient attention output", data.output, batch_size, sequence_length, num_heads, head_size); @@ -955,38 +699,6 @@ template Status LaunchUnpackQKV( const int kv_num_heads, const int head_size, const int sequence_length, const int batch_size, cudaStream_t stream, const int max_threads_per_block); -template Status LaunchConcatKVInPlace(int batch_size, - int kv_num_heads, - int head_size, - int max_sequence_length, - const int* seqlens_k, - const int* total_seqlens_k, - int new_seq_len, - const half* new_key, - const half* new_value, - half* present_key, - half* present_value, - bool is_past_kv_bnsh_format, - bool is_new_kv_bnsh_format, - cudaStream_t stream, - const int max_threads_per_block); - -template Status LaunchConcatKVInPlace(int batch_size, - int kv_num_heads, - int head_size, - int max_sequence_length, - const int* seqlens_k, - const int* total_seqlens_k, - int new_seq_len, - const BFloat16* new_key, - const BFloat16* new_value, - BFloat16* present_key, - BFloat16* present_value, - bool is_past_kv_bnsh_format, - bool is_new_kv_bnsh_format, - cudaStream_t stream, - const int max_threads_per_block); - } // namespace cuda } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/group_query_attention_impl.h b/onnxruntime/contrib_ops/cuda/bert/group_query_attention_impl.h index 8593ecede2bab..4ae4c450902f8 100644 --- a/onnxruntime/contrib_ops/cuda/bert/group_query_attention_impl.h +++ b/onnxruntime/contrib_ops/cuda/bert/group_query_attention_impl.h @@ -6,43 +6,15 @@ #include #include #include "contrib_ops/cpu/bert/attention_common.h" +#include "contrib_ops/cpu/bert/attention_parameters.h" +#include "contrib_ops/cuda/bert/attention_data.h" +#include "contrib_ops/cuda/bert/attention_kv_cache.h" #include "core/framework/allocator.h" namespace onnxruntime { namespace contrib { namespace cuda { -template -struct GroupQueryAttentionData { - // Input Tensors - const T* query = nullptr; - const T* key = nullptr; - const T* value = nullptr; - const T* past_key = nullptr; - const T* past_value = nullptr; - int* seqlens_k = nullptr; - const T* cos_cache = nullptr; - const T* sin_cache = nullptr; - // Flash buffers - T* softmax_lse = nullptr; - T* softmax_lse_accum = nullptr; - T* out_accum = nullptr; - int* seqlens_k_buff = nullptr; - // Memory Efficient buffers - T* fmha_buffer = nullptr; - T* unpacked_qkv_buffer = nullptr; - T* rotary_buffer = nullptr; - T* k = nullptr; - T* v = nullptr; - // Output Tensors - T* output = nullptr; - T* present_key = nullptr; - T* present_value = nullptr; - // Kernel Flags - bool use_flash_attention = false; - bool use_memory_efficient_attention = false; -}; - template Status QkvToContext( const cudaDeviceProp& device_prop, @@ -56,23 +28,6 @@ Status LaunchUnpackQKV(const T* packed_qkv, T* unpacked_q, T* unpacked_k, T* unp const int kv_num_heads, const int head_size, const int sequence_length, const int batch_size, cudaStream_t stream, const int max_threads_per_block); -template -Status LaunchConcatKVInPlace(int batch_size, - int kv_num_heads, - int head_size, - int max_sequence_length, // max sequence length of present_key or present_value. - const int* seqlens_k, // it is not used when total_seqlens_k is available. - const int* total_seqlens_k, // optional, nullptr means it is not available. - int new_seq_len, - const T* new_key, - const T* new_value, - T* present_key, - T* present_value, - bool is_past_kv_bnsh_format, - bool is_new_kv_bnsh_format, - cudaStream_t stream, - const int max_threads_per_block); - } // namespace cuda } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/multihead_attention.cc b/onnxruntime/contrib_ops/cuda/bert/multihead_attention.cc index e2587d172af94..130a0c1e4c00e 100644 --- a/onnxruntime/contrib_ops/cuda/bert/multihead_attention.cc +++ b/onnxruntime/contrib_ops/cuda/bert/multihead_attention.cc @@ -2,12 +2,14 @@ // Licensed under the MIT License. #include "core/providers/cuda/cuda_common.h" +#include "contrib_ops/cpu/bert/multihead_attention_helper.h" +#include "contrib_ops/cpu/utils/dump_tensor.h" #include "contrib_ops/cuda/bert/attention_impl.h" #include "contrib_ops/cuda/bert/multihead_attention.h" -#include "contrib_ops/cpu/bert/multihead_attention_helper.h" #include "contrib_ops/cuda/bert/cutlass_fmha/memory_efficient_attention.h" #include "contrib_ops/cuda/bert/cudnn_fmha/cudnn_flash_attention.h" #include "contrib_ops/cuda/bert/flash_attention/flash_api.h" +#include "contrib_ops/cuda/bert/fastertransformer_decoder_attention/decoder_masked_multihead_attention_impl.h" #include "contrib_ops/cuda/utils/dump_cuda_tensor.h" #include "contrib_ops/cuda/bert/lean_attention/lean_api.h" @@ -19,22 +21,26 @@ namespace onnxruntime { namespace contrib { namespace cuda { -#define REGISTER_KERNEL_TYPED(T) \ - ONNX_OPERATOR_TYPED_KERNEL_EX( \ - MultiHeadAttention, \ - kMSDomain, \ - 1, \ - T, \ - kCudaExecutionProvider, \ - (*KernelDefBuilder::Create()) \ - .TypeConstraint("T", DataTypeImpl::GetTensorType()), \ - MultiHeadAttention); - -REGISTER_KERNEL_TYPED(float) -REGISTER_KERNEL_TYPED(MLFloat16) - -template -MultiHeadAttention::MultiHeadAttention(const OpKernelInfo& info) +#define REGISTER_KERNEL_TYPED(T, QK) \ + ONNX_OPERATOR_TYPED_KERNEL_EX( \ + MultiHeadAttention, \ + kMSDomain, \ + 1, \ + T##_##QK, \ + kCudaExecutionProvider, \ + (*KernelDefBuilder::Create()) \ + .TypeConstraint("T", DataTypeImpl::GetTensorType()) \ + .TypeConstraint("QK", DataTypeImpl::GetTensorType()) \ + .InputMemoryType(OrtMemTypeCPUInput, 8), \ + MultiHeadAttention); + +REGISTER_KERNEL_TYPED(float, float) +REGISTER_KERNEL_TYPED(float, MLFloat16) +REGISTER_KERNEL_TYPED(MLFloat16, float) +REGISTER_KERNEL_TYPED(MLFloat16, MLFloat16) + +template +MultiHeadAttention::MultiHeadAttention(const OpKernelInfo& info) : CudaKernel(info), fused_fp16_cross_attention_kernel_(nullptr), cumulated_sequence_length_q_cache_(), @@ -65,6 +71,8 @@ MultiHeadAttention::MultiHeadAttention(const OpKernelInfo& info) enable_cudnn_flash_attention_ = sizeof(T) == 2 && kernel_options_->UseCudnnFlashAttention(); + disable_decoder_attention_ = !kernel_options_->UseDecoderAttention(); + // Allocate cache buffers constexpr size_t cache_bytes = sizeof(int32_t) * (static_cast(kCumulatedSequenceLengthCacheMaxBatchSize) + 1); cumulated_sequence_length_q_cache_.buffer = GetTransientScratchBuffer(cache_bytes); @@ -73,8 +81,8 @@ MultiHeadAttention::MultiHeadAttention(const OpKernelInfo& info) cumulated_sequence_length_kv_cache_.max_batch_size = kCumulatedSequenceLengthCacheMaxBatchSize; } -template -Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { +template +Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { const Tensor* query = context->Input(0); const Tensor* key = context->Input(1); const Tensor* value = context->Input(2); @@ -83,6 +91,13 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { const Tensor* attention_bias = context->Input(5); const Tensor* past_key = context->Input(6); const Tensor* past_value = context->Input(7); + const Tensor* past_sequence_length = context->Input(8); + const Tensor* cache_indirection = context->Input(9); + + bool past_present_share_buffer = past_key != nullptr && past_sequence_length != nullptr; + if (past_key != nullptr && past_sequence_length != nullptr && cache_indirection != nullptr) { + ORT_ENFORCE(past_present_share_buffer); + } auto& device_prop = GetDeviceProp(); AttentionParameters parameters; @@ -96,15 +111,29 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { attention_bias, past_key, past_value, - nullptr, // past_seq_len + cache_indirection, + past_sequence_length, ¶meters, num_heads_, mask_filter_value_, scale_, is_unidirectional_, - false, // past_present_share_buffer + past_present_share_buffer, kMultiHeadAttention, device_prop.maxThreadsPerBlock)); + DUMP_STRING_INIT(); + DUMP_STRING("Batch size = ", parameters.batch_size); + DUMP_STRING("Sequence length = ", parameters.sequence_length); + DUMP_STRING("Past sequence length = ", parameters.past_sequence_length); + DUMP_STRING("KV sequence length = ", parameters.kv_sequence_length); + DUMP_STRING("Total sequence length = ", parameters.total_sequence_length); + DUMP_STRING("Max sequence length = ", parameters.max_sequence_length); + DUMP_STRING("Hidden size = ", parameters.hidden_size); + DUMP_STRING("Head size = ", parameters.head_size); + DUMP_STRING("Num heads = ", parameters.num_heads); + DUMP_STRING("Buffer sharing = ", (parameters.past_present_share_buffer == true)); + DUMP_STRING("QKV format = ", parameters.qkv_format); + int sequence_length = parameters.sequence_length; TensorShapeVector output_shape(3); @@ -114,11 +143,16 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { Tensor* output = context->Output(0, output_shape); std::vector present_dims{ - parameters.batch_size, parameters.num_heads, parameters.total_sequence_length, parameters.head_size}; + parameters.batch_size, parameters.num_heads, parameters.max_sequence_length, parameters.head_size}; TensorShape present_shape(present_dims); Tensor* present_key = context->Output(1, present_shape); Tensor* present_value = context->Output(2, present_shape); + std::vector output_qk_dims{ + parameters.batch_size, parameters.num_heads, parameters.sequence_length, parameters.total_sequence_length}; + TensorShape output_qk_shape(output_qk_dims); + Tensor* output_qk = context->Output(3, output_qk_shape); + int num_past = static_cast(past_key != nullptr) + static_cast(past_value != nullptr); int num_present = static_cast(present_key != nullptr) + static_cast(present_value != nullptr); if (num_past == 0 && num_present == 0) { @@ -155,6 +189,51 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { int sm = device_prop.major * 10 + device_prop.minor; AttentionKernelType kernel_type = AttentionKernelType::AttentionKernel_Default; + cudaStream_t stream = Stream(context); + + bool use_decoder_masked_multihead_attention = false; + if (cache_indirection != nullptr) { + bool use_dmmha_self_attention = parameters.qkv_format == AttentionQkvFormat::Q_K_V_BSNH && + parameters.past_present_share_buffer && + parameters.past_sequence_length > 0; + bool use_dmmha_cross_attention = parameters.qkv_format == AttentionQkvFormat::Q_K_V_BSNH_BNSH_BNSH && + past_key == nullptr && past_value == nullptr && nullptr != past_sequence_length && + parameters.past_sequence_length != *((*past_sequence_length).template Data()); + use_decoder_masked_multihead_attention = !disable_decoder_attention_ && + (std::is_same::value || std::is_same::value) && + (use_dmmha_self_attention || use_dmmha_cross_attention) && + parameters.sequence_length == 1 && + parameters.head_size == parameters.v_head_size && + (parameters.mask_type == AttentionMaskType::MASK_2D_KEY_PADDING || parameters.mask_type == AttentionMaskType::MASK_NONE) && + nullptr != past_sequence_length && nullptr != cache_indirection && + has_decoder_masked_multihead_attention(sm, parameters.head_size); + } + DUMP_STRING("Use DMMHA = ", (use_decoder_masked_multihead_attention == true)); + if (use_decoder_masked_multihead_attention) { + // Kernel only works for token generation with beam search + kernel_type = AttentionKernelType::AttentionKernel_DecoderAttention; + + // No production use-case will incur this copy cost as the implementation of + // DecoderMaskedMultiHeadAttention is written in such a way that the past and present buffers + // must be shared to have parity in the outputs. + // This is just to circumvent the OpTester's limitation of not being able to bind a specific + // buffer to inputs/outputs. + auto* past_key_data = (past_key == nullptr) ? nullptr : past_key->Data(); + auto* past_value_data = (past_value == nullptr) ? nullptr : past_value->Data(); + auto* present_key_data = (present_key == nullptr) ? nullptr : present_key->MutableData(); + auto* present_value_data = (present_value == nullptr) ? nullptr : present_value->MutableData(); + + if (present_key_data != past_key_data) { + DUMP_STRING("Copying past_key to present_key for OpTester"); + CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(present_key_data, past_key_data, past_key->SizeInBytes(), + cudaMemcpyDeviceToDevice, stream)); + } + if (present_value_data != past_value_data) { + DUMP_STRING("Copying past_value to present_value for OpTester"); + CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(present_value_data, past_value_data, past_value->SizeInBytes(), + cudaMemcpyDeviceToDevice, stream)); + } + } typedef typename ToCudaType::MappedType CudaT; AttentionData data; @@ -179,6 +258,7 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { parameters.num_heads); size_t sync_flag_bytes = 0; + DUMP_STRING("Use lean attn = ", (use_lean_attention == true)); if (use_lean_attention) { softmax_lse_bytes = onnxruntime::lean::get_softmax_lse_size(parameters.sequence_length, parameters.batch_size, @@ -216,12 +296,16 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { !disable_flash_attention_ && nullptr == attention_bias && nullptr == key_padding_mask && + nullptr == past_sequence_length && + nullptr == cache_indirection && + nullptr == output_qk && parameters.head_size == parameters.v_head_size && onnxruntime::flash::is_supported(device_prop, parameters.head_size, parameters.num_heads, parameters.num_heads); // When input is packed QKV format, TensorRT kernel might be faster than flash attention when sequence length <= 512. + DUMP_STRING("Use flash attn = ", (use_flash_attention == true)); if (use_flash_attention && parameters.qkv_format == AttentionQkvFormat::QKV_BS3NH && parameters.sequence_length < kernel_options_->MinSeqLenForFlashAttentionPackedQkv()) { use_flash_attention = false; @@ -270,6 +354,7 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { parameters.sequence_length, // seq_len_q parameters.total_sequence_length, // seq_len_kv is_unidirectional_); + DUMP_STRING("Use cuDNN SDPA = ", (use_cudnn_sdpa == true)); if (use_cudnn_sdpa) { kernel_type = AttentionKernelType::AttentionKernel_CudnnFlashAttention; } @@ -280,10 +365,16 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { !is_unidirectional_ && nullptr == key_padding_mask && nullptr == attention_bias && - nullptr == past_key && nullptr == present_key && + nullptr == past_key && + nullptr == past_sequence_length && + nullptr == cache_indirection && + nullptr == present_key && + nullptr == output_qk && (parameters.qkv_format == Q_K_V_BSNH || (parameters.qkv_format == Q_KV_BSNH_BSN2H && bias == nullptr)) && parameters.hidden_size == parameters.v_hidden_size && has_fused_cross_attention_kernel(sm, parameters.head_size, parameters.kv_sequence_length); + + DUMP_STRING("Use fused cross attn = ", (use_fused_cross_attention == true)); if (use_fused_cross_attention) { if (fused_fp16_cross_attention_kernel_ == nullptr) { std::call_once(fused_cross_init_once_flag_, [&]() { @@ -305,12 +396,15 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { !is_unidirectional_ && nullptr == attention_bias && (parameters.qkv_format == Q_K_V_BSNH || parameters.qkv_format == QKV_BSN3H) && - nullptr == past_key && nullptr == present_key && + nullptr == past_key && nullptr == past_sequence_length && nullptr == cache_indirection && + nullptr == present_key && nullptr == output_qk && is_mask_none_or_1d_k_len && parameters.hidden_size == parameters.v_hidden_size && parameters.sequence_length == parameters.kv_sequence_length && // self attention only for fused runner FusedMHARunnerFP16v2::IsSupported(sm, parameters.head_size, sequence_length, enable_trt_flash_attention_, is_unidirectional_); + + DUMP_STRING("Use fused runner = ", (use_fused_runner == true)); if (use_fused_runner) { // Here we assume that num_heads and head_size does not change for a MultiHeadAttention node. if (nullptr == fused_fp16_runner_.get()) { @@ -342,8 +436,10 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { // Check whether the attention bias alignment is good for memory efficient attention. (attention_bias == nullptr || parameters.sequence_length % (4 * sizeof(T)) == 0) && (nullptr == key_padding_mask || parameters.mask_type == AttentionMaskType::MASK_1D_KEY_SEQ_LEN_START) && + nullptr == past_sequence_length && nullptr == cache_indirection && nullptr == output_qk && has_memory_efficient_attention(sm, std::is_same::value, parameters.head_size, parameters.v_head_size); + DUMP_STRING("Use memory efficient attention = ", (use_memory_efficient_attention == true)); if (use_memory_efficient_attention) { kernel_type = AttentionKernelType::AttentionKernel_CutlassMemoryEfficientAttention; } @@ -355,6 +451,7 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { kernel_type = AttentionKernelType::AttentionKernel_Unfused; } + typedef typename ToCudaType::MappedType CudaQK; data.bias = (nullptr == bias) ? nullptr : reinterpret_cast(bias->Data()); data.query = reinterpret_cast(query->Data()); data.key = (nullptr == key) ? nullptr : reinterpret_cast(key->Data()); @@ -366,21 +463,27 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { if (nullptr != attention_bias) { data.attention_bias = reinterpret_cast(attention_bias->Data()); } + if (nullptr != cache_indirection) { + data.cache_indirection = reinterpret_cast(cache_indirection->Data()); + } data.output = reinterpret_cast(output->MutableData()); data.present_key = (nullptr == present_key) ? nullptr : reinterpret_cast(present_key->MutableData()); data.present_value = (nullptr == present_value) ? nullptr : reinterpret_cast(present_value->MutableData()); + if (nullptr != output_qk) { + data.output_qk = reinterpret_cast(output_qk->MutableData()); + } data.fused_runner = reinterpret_cast(fused_runner); data.fused_cross_attention_kernel = fused_cross_attention_kernel; data.use_flash_attention = use_flash_attention; data.use_lean_attention = use_lean_attention; data.use_memory_efficient_attention = use_memory_efficient_attention; + data.use_decoder_masked_multihead_attention = use_decoder_masked_multihead_attention; data.kernel_type = kernel_type; data.allocator = Info().GetAllocator(OrtMemType::OrtMemTypeDefault); // Cache of cumulated sequence length that could help when sequence length does not change (for example, image model). // The cache will be initialized only once, and become readonly after that. if ((data.fused_cross_attention_kernel != nullptr || data.fused_runner != nullptr) && data.mask_index == nullptr) { - cudaStream_t stream = Stream(context); data.cumulated_sequence_length_q_cache = this->cumulated_sequence_length_q_cache_.TryGet( parameters.batch_size, parameters.sequence_length, stream); @@ -414,6 +517,18 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { data.allow_debug_info = kernel_options_->AllowDebugInfo(); + // For past-present buffer sharing. + if (parameters.past_present_share_buffer) { + std::vector seqlens_k(parameters.batch_size, parameters.total_sequence_length - 1); + size_t seqlens_k_bytes = 0; + seqlens_k_bytes = sizeof(int) * parameters.batch_size; + auto seqlens_k_buffer = GetScratchBuffer(seqlens_k_bytes, context->GetComputeStream()); + if (seqlens_k_buffer != nullptr) { + data.seqlens_k_total = reinterpret_cast(seqlens_k_buffer.get()); + CUDA_RETURN_IF_ERROR(cudaMemcpy(data.seqlens_k_total, seqlens_k.data(), seqlens_k_bytes, cudaMemcpyHostToDevice)); + } + } + if (data.allow_debug_info) { AttentionKernelDebugInfo debug_info; debug_info.use_flash_attention = use_flash_attention; @@ -434,7 +549,8 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { cublasHandle_t cublas = GetCublasHandle(context); cudnnHandle_t cudnn = GetCudnnHandle(context); - return QkvToContext( + DUMP_STRING("Run QkvToContext from MHA CUDA"); + return QkvToContext( device_prop, cublas, cudnn, context->GetComputeStream(), parameters, data); } diff --git a/onnxruntime/contrib_ops/cuda/bert/multihead_attention.h b/onnxruntime/contrib_ops/cuda/bert/multihead_attention.h index b093b226c50b0..7de27c24fb601 100644 --- a/onnxruntime/contrib_ops/cuda/bert/multihead_attention.h +++ b/onnxruntime/contrib_ops/cuda/bert/multihead_attention.h @@ -17,7 +17,7 @@ namespace cuda { using namespace onnxruntime::cuda; -template +template class MultiHeadAttention final : public CudaKernel { public: MultiHeadAttention(const OpKernelInfo& info); @@ -37,6 +37,7 @@ class MultiHeadAttention final : public CudaKernel { #endif bool disable_memory_efficient_attention_; bool enable_cudnn_flash_attention_; + bool disable_decoder_attention_; // These mutable members are readonly after they are initialized so that they can be shared among multiple threads. // Initialization are done only once by the first thread using the resource, so use once_flag to guard each resource. diff --git a/onnxruntime/contrib_ops/cuda/bert/packed_attention.h b/onnxruntime/contrib_ops/cuda/bert/packed_attention.h index 6fcacd4d46ada..0f7456d0cd0d8 100644 --- a/onnxruntime/contrib_ops/cuda/bert/packed_attention.h +++ b/onnxruntime/contrib_ops/cuda/bert/packed_attention.h @@ -9,6 +9,7 @@ #include "core/providers/cuda/cuda_kernel.h" #include "contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/mha_runner.h" #include "contrib_ops/cpu/bert/attention_common.h" +#include "contrib_ops/cpu/bert/attention_parameters.h" #include "contrib_ops/cuda/bert/attention_kernel_options.h" namespace onnxruntime { diff --git a/onnxruntime/contrib_ops/cuda/bert/packed_attention_impl.h b/onnxruntime/contrib_ops/cuda/bert/packed_attention_impl.h index 1126c8a046da9..711718016486f 100644 --- a/onnxruntime/contrib_ops/cuda/bert/packed_attention_impl.h +++ b/onnxruntime/contrib_ops/cuda/bert/packed_attention_impl.h @@ -6,6 +6,8 @@ #include #include #include "contrib_ops/cpu/bert/attention_common.h" +#include "contrib_ops/cpu/bert/attention_parameters.h" +#include "contrib_ops/cuda/bert/attention_data.h" namespace onnxruntime { namespace contrib { @@ -29,22 +31,6 @@ size_t GetAttentionWorkspaceSize( bool use_memory_efficient_attention, bool no_qkv_workspace); -template -struct PackedAttentionData { - T* gemm_buffer; - const T* bias; - const T* attention_bias; - const int32_t* token_offset; - const int32_t* cumulative_sequence_length; - - T* workspace; - T* output; - - void* fused_runner; - - bool use_memory_efficient_attention; -}; - template Status QkvToContext( const cudaDeviceProp& device_prop, diff --git a/onnxruntime/contrib_ops/cuda/bert/packed_multihead_attention_impl.cu b/onnxruntime/contrib_ops/cuda/bert/packed_multihead_attention_impl.cu index f3b9fd310f46f..846d2be7bf2e1 100644 --- a/onnxruntime/contrib_ops/cuda/bert/packed_multihead_attention_impl.cu +++ b/onnxruntime/contrib_ops/cuda/bert/packed_multihead_attention_impl.cu @@ -698,8 +698,8 @@ Status FusedAttentionCutlass( p.scale = parameters.scale == 0.0f ? 1.f / sqrt(static_cast(qk_head_size)) : parameters.scale; p.seqlen_k_ptr = nullptr; - p.seqstart_q_ptr = const_cast(data.cumulative_sequence_length); - p.seqstart_k_ptr = const_cast(data.cumulative_sequence_length); + p.seqstart_q_ptr = data.cumulative_sequence_length; + p.seqstart_k_ptr = data.cumulative_sequence_length; p.query = data.no_qkv_workspace ? data.query : data.workspace; p.key = data.no_qkv_workspace ? data.key : (data.workspace + elements_qk); p.value = data.no_qkv_workspace ? data.value : (data.workspace + elements_qk + elements_qk); diff --git a/onnxruntime/contrib_ops/cuda/bert/packed_multihead_attention_impl.h b/onnxruntime/contrib_ops/cuda/bert/packed_multihead_attention_impl.h index 9d0ff77e5fcaa..10e95b95657f1 100644 --- a/onnxruntime/contrib_ops/cuda/bert/packed_multihead_attention_impl.h +++ b/onnxruntime/contrib_ops/cuda/bert/packed_multihead_attention_impl.h @@ -6,34 +6,13 @@ #include #include #include "contrib_ops/cpu/bert/attention_common.h" +#include "contrib_ops/cpu/bert/attention_parameters.h" +#include "contrib_ops/cuda/bert/attention_data.h" namespace onnxruntime { namespace contrib { namespace cuda { -template -struct PackedMultiHeadAttentionData { - const T* query; - const T* key; - const T* value; - const T* bias; - const T* attention_bias; - - const int32_t* token_offset; - const int32_t* cumulative_sequence_length; - - AttentionQkvFormat source_qkv_format; - - bool no_qkv_workspace; - T* workspace; - T* output; - - void* fused_runner; - - bool use_flash_attention; - bool use_memory_efficient_attention; -}; - template Status QkvToContext( const cudaDeviceProp& device_prop, diff --git a/onnxruntime/contrib_ops/cuda/cuda_contrib_kernels.cc b/onnxruntime/contrib_ops/cuda/cuda_contrib_kernels.cc index cbe4d87dbf398..b8931bf1ea0f8 100644 --- a/onnxruntime/contrib_ops/cuda/cuda_contrib_kernels.cc +++ b/onnxruntime/contrib_ops/cuda/cuda_contrib_kernels.cc @@ -92,8 +92,10 @@ class CUDA_ONNX_OP_TYPED_CLASS_NAME(1, MLFloat16, Crop); class CUDA_MS_OP_TYPED_CLASS_NAME(1, float, MoE); class CUDA_MS_OP_TYPED_CLASS_NAME(1, MLFloat16, MoE); class CUDA_MS_OP_CLASS_NAME(1, QMoE); -class CUDA_MS_OP_TYPED_CLASS_NAME(1, float, MultiHeadAttention); -class CUDA_MS_OP_TYPED_CLASS_NAME(1, MLFloat16, MultiHeadAttention); +class CUDA_MS_OP_TYPED_CLASS_NAME(1, float_float, MultiHeadAttention); +class CUDA_MS_OP_TYPED_CLASS_NAME(1, float_MLFloat16, MultiHeadAttention); +class CUDA_MS_OP_TYPED_CLASS_NAME(1, MLFloat16_float, MultiHeadAttention); +class CUDA_MS_OP_TYPED_CLASS_NAME(1, MLFloat16_MLFloat16, MultiHeadAttention); class CUDA_MS_OP_TYPED_CLASS_NAME(1, MLFloat16, GroupQueryAttention); class CUDA_MS_OP_TYPED_CLASS_NAME(1, BFloat16, GroupQueryAttention); class CUDA_MS_OP_TYPED_CLASS_NAME(1, float, DecoderAttention); @@ -169,8 +171,10 @@ class CUDA_MS_OP_CLASS_NAME(1, QOrderedAttention); class CUDA_MS_OP_CLASS_NAME(1, QOrderedLongformerAttention); class CUDA_MS_OP_TYPED_CLASS_NAME(1, float, DecoderMaskedSelfAttention); class CUDA_MS_OP_TYPED_CLASS_NAME(1, MLFloat16, DecoderMaskedSelfAttention); -class CUDA_MS_OP_TYPED_CLASS_NAME(1, float, DecoderMaskedMultiHeadAttention); -class CUDA_MS_OP_TYPED_CLASS_NAME(1, MLFloat16, DecoderMaskedMultiHeadAttention); +class CUDA_MS_OP_TYPED_CLASS_NAME(1, float_float, DecoderMaskedMultiHeadAttention); +class CUDA_MS_OP_TYPED_CLASS_NAME(1, float_MLFloat16, DecoderMaskedMultiHeadAttention); +class CUDA_MS_OP_TYPED_CLASS_NAME(1, MLFloat16_float, DecoderMaskedMultiHeadAttention); +class CUDA_MS_OP_TYPED_CLASS_NAME(1, MLFloat16_MLFloat16, DecoderMaskedMultiHeadAttention); class CUDA_MS_OP_CLASS_NAME(1, GemmFloat8); class CUDA_MS_OP_TYPED_CLASS_NAME(1, MLFloat16, SparseAttention); class CUDA_MS_OP_TYPED_CLASS_NAME(1, BFloat16, SparseAttention); @@ -298,8 +302,10 @@ Status RegisterCudaContribKernels(KernelRegistry& kernel_registry) { BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, @@ -381,8 +387,10 @@ Status RegisterCudaContribKernels(KernelRegistry& kernel_registry) { BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, diff --git a/onnxruntime/contrib_ops/cuda/sparse/sparse_attention_impl.cu b/onnxruntime/contrib_ops/cuda/sparse/sparse_attention_impl.cu index 4cb25af970599..e55163186b505 100644 --- a/onnxruntime/contrib_ops/cuda/sparse/sparse_attention_impl.cu +++ b/onnxruntime/contrib_ops/cuda/sparse/sparse_attention_impl.cu @@ -7,6 +7,7 @@ #include "contrib_ops/cuda/bert/group_query_attention_impl.h" #include "contrib_ops/cpu/bert/attention_common.h" #include "contrib_ops/cuda/bert/attention_impl.h" +#include "contrib_ops/cuda/bert/attention_kv_cache.h" #include "contrib_ops/cuda/sparse/sparse_attention_v1/sparse_attention_common.h" #include "contrib_ops/cuda/sparse/sparse_attention_v1/sparse_attention_v1_api.h" #include "contrib_ops/cuda/sparse/sparse_attention_v2/sparse_attention_v2_api.h" diff --git a/onnxruntime/contrib_ops/cuda/sparse/sparse_attention_impl.h b/onnxruntime/contrib_ops/cuda/sparse/sparse_attention_impl.h index 0b07b234b7315..d4f686afe5db0 100644 --- a/onnxruntime/contrib_ops/cuda/sparse/sparse_attention_impl.h +++ b/onnxruntime/contrib_ops/cuda/sparse/sparse_attention_impl.h @@ -6,6 +6,7 @@ #include #include "core/providers/cuda/shared_inc/cuda_utils.h" #include "contrib_ops/cpu/bert/attention_common.h" +#include "contrib_ops/cpu/bert/attention_parameters.h" #include "core/framework/allocator.h" #include "core/providers/cuda/tunable/cuda_tunable.h" diff --git a/onnxruntime/contrib_ops/cuda/transformers/generation_device_helper.cc b/onnxruntime/contrib_ops/cuda/transformers/generation_device_helper.cc index 23283706a11cf..f7ed758aedbb2 100644 --- a/onnxruntime/contrib_ops/cuda/transformers/generation_device_helper.cc +++ b/onnxruntime/contrib_ops/cuda/transformers/generation_device_helper.cc @@ -1360,6 +1360,7 @@ Status ExpandBuffer(Stream* ort_stream, // Input shape (batch_size, xxx). The input is required with data type T. // Output shape (batch_size * num_beams, xxx) const TensorShape& input_shape = input.Get().Shape(); + const int64_t& batch_size = input_shape[0]; int64_t sequence_length = 0; diff --git a/onnxruntime/contrib_ops/rocm/bert/attention_impl.h b/onnxruntime/contrib_ops/rocm/bert/attention_impl.h index 6c2e36b596d32..3053521ad946e 100644 --- a/onnxruntime/contrib_ops/rocm/bert/attention_impl.h +++ b/onnxruntime/contrib_ops/rocm/bert/attention_impl.h @@ -6,6 +6,7 @@ #include #include #include "contrib_ops/cpu/bert/attention_common.h" +#include "contrib_ops/cpu/bert/attention_parameters.h" #include "core/providers/rocm/shared_inc/rocm_utils.h" #include "core/providers/rocm/tunable/rocm_tunable.h" diff --git a/onnxruntime/contrib_ops/rocm/bert/attention_softmax.h b/onnxruntime/contrib_ops/rocm/bert/attention_softmax.h index 5bcd46f9b9ea8..9f2faa228cf79 100644 --- a/onnxruntime/contrib_ops/rocm/bert/attention_softmax.h +++ b/onnxruntime/contrib_ops/rocm/bert/attention_softmax.h @@ -40,7 +40,7 @@ template __device__ inline void Softmax(const int all_sequence_length, const int valid_end, const int valid_start, - const T* add_before_softmax, + const T* attn_bias, const T* input, T* output) { using BlockReduce = hipcub::BlockReduce; @@ -59,9 +59,9 @@ __device__ inline void Softmax(const int all_sequence_length, for (int i = threadIdx.x; i < valid_end; i += TPB) { if (i >= valid_start) { const int index = offset + i; - float input_at_idx = add_before_softmax == nullptr + float input_at_idx = attn_bias == nullptr ? static_cast(input[index]) - : static_cast(input[index] + add_before_softmax[index]); + : static_cast(input[index] + attn_bias[index]); if (thread_data_max < input_at_idx) { thread_data_max = input_at_idx; } @@ -80,7 +80,7 @@ __device__ inline void Softmax(const int all_sequence_length, for (int i = threadIdx.x; i < valid_end; i += TPB) { if (i >= valid_start) { const int index = offset + i; - float val = add_before_softmax == nullptr ? input[index] : input[index] + add_before_softmax[index]; + float val = attn_bias == nullptr ? input[index] : input[index] + attn_bias[index]; thread_data_sum += expf(val - max_block); } } @@ -93,9 +93,9 @@ __device__ inline void Softmax(const int all_sequence_length, for (int i = threadIdx.x; i < all_sequence_length; i += TPB) { const int index = offset + i; - float input_at_idx = add_before_softmax == nullptr + float input_at_idx = attn_bias == nullptr ? static_cast(input[index]) - : static_cast(input[index] + add_before_softmax[index]); + : static_cast(input[index] + attn_bias[index]); const float val = (i >= valid_start && i < valid_end) ? expf(input_at_idx - max_block) * sum_reverse_block : 0.f; output[index] = T(val); } @@ -106,7 +106,7 @@ __device__ inline void SoftmaxSmall(const int all_sequence_length, const int sequence_length, const int valid_end, const int valid_start, - const T* add_before_softmax, + const T* attn_bias, const T* input, T* output, bool causal) { @@ -137,9 +137,9 @@ __device__ inline void SoftmaxSmall(const int all_sequence_length, // Infinity divided by Infinity is a NAN. Thus, softmax gets a NAN if one or more item are large enough. // a math transform as below is leveraged to get a stable softmax: // e^xi/(e^x1 + ...e^xn) = e^(xi - max) / (e^(x1 - max) + ... + e^(xn - max)) - float input_data = add_before_softmax == nullptr + float input_data = attn_bias == nullptr ? static_cast(input[index]) - : static_cast(input[index] + add_before_softmax[index]); + : static_cast(input[index] + attn_bias[index]); float thread_data_max = is_valid ? input_data : float(-ROCMRT_INF_F); const auto max = BlockReduce(tmp_storage).Reduce(thread_data_max, hipcub::Max(), end); @@ -178,7 +178,7 @@ __global__ void SoftmaxWithRawMaskSmallKernel( const int3 attention_mask_strides, const int* attention_mask, // 2D, 3D or 4D attention mask const bool* key_padding_mask, - const T* add_before_softmax, + const T* attn_bias, const T* input, T* output, const bool causal, @@ -225,8 +225,8 @@ __global__ void SoftmaxWithRawMaskSmallKernel( } } - if (add_before_softmax != nullptr) { - thread_data += float(add_before_softmax[index]); + if (attn_bias != nullptr) { + thread_data += float(attn_bias[index]); } } @@ -264,50 +264,50 @@ __global__ void SoftmaxWithRawMaskSmallKernel( template __global__ void SoftmaxKernelSmall(const int all_sequence_length, const int sequence_length, - const T* add_before_softmax, const T* input, T* output, bool causal) { + const T* attn_bias, const T* input, T* output, bool causal) { SoftmaxSmall(all_sequence_length, sequence_length, all_sequence_length, 0, - add_before_softmax, input, output, causal); + attn_bias, input, output, causal); } template -__global__ void SoftmaxKernel(const int all_sequence_length, const T* add_before_softmax, const T* input, T* output) { - Softmax(all_sequence_length, all_sequence_length, 0, add_before_softmax, input, output); +__global__ void SoftmaxKernel(const int all_sequence_length, const T* attn_bias, const T* input, T* output) { + Softmax(all_sequence_length, all_sequence_length, 0, attn_bias, input, output); } template Status ComputeSoftmax( hipStream_t stream, const int all_sequence_length, const int sequence_length, const int batch_size, const int num_heads, - const T* add_before_softmax, const T* input, T* output, bool causal) { + const T* attn_bias, const T* input, T* output, bool causal) { const dim3 grid(sequence_length * num_heads, batch_size, 1); if (all_sequence_length <= 32) { const int blockSize = 32; SoftmaxKernelSmall<<>>( - all_sequence_length, sequence_length, add_before_softmax, input, output, causal); + all_sequence_length, sequence_length, attn_bias, input, output, causal); } else if (all_sequence_length <= 64) { const int blockSize = 64; SoftmaxKernelSmall<<>>( - all_sequence_length, sequence_length, add_before_softmax, input, output, causal); + all_sequence_length, sequence_length, attn_bias, input, output, causal); } else if (all_sequence_length <= 128) { const int blockSize = 128; SoftmaxKernelSmall<<>>( - all_sequence_length, sequence_length, add_before_softmax, input, output, causal); + all_sequence_length, sequence_length, attn_bias, input, output, causal); } else if (all_sequence_length <= 256) { const int blockSize = 256; SoftmaxKernelSmall<<>>( - all_sequence_length, sequence_length, add_before_softmax, input, output, causal); + all_sequence_length, sequence_length, attn_bias, input, output, causal); } else if (all_sequence_length <= 512) { const int blockSize = 512; SoftmaxKernelSmall<<>>( - all_sequence_length, sequence_length, add_before_softmax, input, output, causal); + all_sequence_length, sequence_length, attn_bias, input, output, causal); } else if (all_sequence_length <= 1024) { const int blockSize = 1024; SoftmaxKernelSmall<<>>( - all_sequence_length, sequence_length, add_before_softmax, input, output, causal); + all_sequence_length, sequence_length, attn_bias, input, output, causal); } else if (!causal) { const int blockSize = 1024; SoftmaxKernel<<>>( - all_sequence_length, add_before_softmax, input, output); + all_sequence_length, attn_bias, input, output); } else { return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Attention ROCM operator does not support total sequence length > 1024."); } @@ -318,7 +318,7 @@ Status ComputeSoftmax( template __global__ void MaskedSoftmaxKernelSmall(const int all_sequence_length, const int sequence_length, const int* mask_end, const int* mask_start, - const T* add_before_softmax, const T* input, T* output, + const T* attn_bias, const T* input, T* output, bool causal) { __shared__ int start_position; __shared__ int end_position; @@ -337,12 +337,12 @@ __global__ void MaskedSoftmaxKernelSmall(const int all_sequence_length, const in __syncthreads(); SoftmaxSmall(all_sequence_length, sequence_length, end_position, start_position, - add_before_softmax, input, output, causal); + attn_bias, input, output, causal); } template __global__ void MaskedSoftmaxKernel(const int all_sequence_length, const int* mask_end, const int* mask_start, - const T* add_before_softmax, const T* input, T* output) { + const T* attn_bias, const T* input, T* output) { __shared__ int start_position; __shared__ int end_position; @@ -359,7 +359,7 @@ __global__ void MaskedSoftmaxKernel(const int all_sequence_length, const int* ma } __syncthreads(); - Softmax(all_sequence_length, end_position, start_position, add_before_softmax, input, output); + Softmax(all_sequence_length, end_position, start_position, attn_bias, input, output); } template @@ -367,13 +367,13 @@ Status ComputeSoftmaxWithMask1D( hipStream_t stream, const int all_sequence_length, const int sequence_length, const int batch_size, const int num_heads, const int* mask_index, const int* mask_start, - const T* add_before_softmax, const T* input, T* output, const bool causal) { + const T* attn_bias, const T* input, T* output, const bool causal) { const dim3 grid(sequence_length * num_heads, batch_size, 1); #define DISPATCH_KERNEL_SMALL_WITH_BLOCKSIZE(block_size) \ MaskedSoftmaxKernelSmall<<>>( \ all_sequence_length, sequence_length, mask_index, mask_start, \ - add_before_softmax, input, output, causal); + attn_bias, input, output, causal); if (all_sequence_length <= 32) { DISPATCH_KERNEL_SMALL_WITH_BLOCKSIZE(32); @@ -391,7 +391,7 @@ Status ComputeSoftmaxWithMask1D( const int blockSize = 1024; MaskedSoftmaxKernel<<>>( all_sequence_length, mask_index, mask_start, - add_before_softmax, input, output); + attn_bias, input, output); } else { return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Attention ROCM operator does not support total sequence length > 1024."); } @@ -410,7 +410,7 @@ Status ComputeSoftmaxWithRawMask(Stream* ort_stream, const int3 attention_mask_strides, const int* attention_mask, const bool* key_padding_mask, - const T* add_before_softmax, + const T* attn_bias, const T* input, T* output, const bool causal, @@ -426,7 +426,7 @@ Status ComputeSoftmaxWithRawMask(Stream* ort_stream, #define DISPATCH_KERNEL_SMALL_WITH_BLOCKSIZE(block_size) \ SoftmaxWithRawMaskSmallKernel<<>>( \ all_sequence_length, sequence_length, attention_mask_strides, \ - attention_mask, key_padding_mask, add_before_softmax, input, out, \ + attention_mask, key_padding_mask, attn_bias, input, out, \ causal, rsqrt_head_size, \ use_persistent_softmax, mask_filter_value); diff --git a/onnxruntime/contrib_ops/rocm/bert/batched_gemm_permute_pipelines.cuh b/onnxruntime/contrib_ops/rocm/bert/batched_gemm_permute_pipelines.cuh index f7709e8242147..66d21e12c2740 100644 --- a/onnxruntime/contrib_ops/rocm/bert/batched_gemm_permute_pipelines.cuh +++ b/onnxruntime/contrib_ops/rocm/bert/batched_gemm_permute_pipelines.cuh @@ -8,6 +8,7 @@ #include "core/providers/rocm/tunable/gemm.h" #include "core/providers/rocm/tunable/rocm_tunable.h" #include "contrib_ops/cpu/bert/attention_common.h" +#include "contrib_ops/cpu/bert/attention_parameters.h" namespace onnxruntime { namespace contrib { diff --git a/onnxruntime/contrib_ops/rocm/bert/multihead_attention.cu b/onnxruntime/contrib_ops/rocm/bert/multihead_attention.cu index fe0d621f1d601..5d4ef53b8ba97 100644 --- a/onnxruntime/contrib_ops/rocm/bert/multihead_attention.cu +++ b/onnxruntime/contrib_ops/rocm/bert/multihead_attention.cu @@ -92,6 +92,8 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { const Tensor* past_value{}; const Tensor* past_seq_len{}; + const Tensor* cache_indirection = nullptr; + if (attn_type_ == kMultiHeadAttention) { bias = context->Input(3); key_padding_mask = context->Input(4); @@ -117,16 +119,24 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { auto& device_prop = GetDeviceProp(); RocmAttentionParameters attn; - ORT_RETURN_IF_ERROR( - multihead_attention_helper::CheckInputs( - query, key, value, bias, - key_padding_mask, attention_bias, - past_key, past_value, past_seq_len, - &attn, num_heads_, - mask_filter_value_, scale_, false, /*is_unidirectional_*/ - past_present_share_buffer_, - attn_type_, - device_prop.maxThreadsPerBlock)); + ORT_RETURN_IF_ERROR(multihead_attention_helper::CheckInputs(query, + key, + value, + bias, + key_padding_mask, + attention_bias, + past_key, + past_value, + cache_indirection, + past_seq_len, + &attn, /* parameters */ + num_heads_, + mask_filter_value_, + scale_, + is_unidirectional_, + past_present_share_buffer_, + attn_type_, + device_prop.maxThreadsPerBlock)); if (attn_type_ == kDecoderMaskedMultiHeadAttention && attn.sequence_length != 1) { return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, diff --git a/onnxruntime/contrib_ops/webgpu/bert/attention.cc b/onnxruntime/contrib_ops/webgpu/bert/attention.cc index 0d4afc8c13f4b..6e7919f281fb6 100644 --- a/onnxruntime/contrib_ops/webgpu/bert/attention.cc +++ b/onnxruntime/contrib_ops/webgpu/bert/attention.cc @@ -99,23 +99,24 @@ Status AttentionProbsProgram::GenerateShaderCode(ShaderHelper& shader) const { << "var tileK: array;\n" << "alias f32_val_t = " << (components_ == 4 ? "vec4" : (components_ == 2 ? "vec2" : "f32")) << ";\n"; shader.MainFunctionBody() << "// x holds the N and y holds the M\n" - << "let m = workgroup_id.y * TILE_SIZE;\n" - << "let n = workgroup_id.x * TILE_SIZE;\n" - << "let batch_idx = workgroup_id.z / uniforms.num_heads;\n" - << "let qOffset = workgroup_id.z * uniforms.M * uniforms.K + m * uniforms.K;\n" + << "let m = u32(workgroup_idx / uniforms.num_total_seq_length_tile) % uniforms.num_seq_length_tile * TILE_SIZE;\n" + << "let n = (workgroup_idx % uniforms.num_total_seq_length_tile) * TILE_SIZE;\n" + << "let batch_head_idx = u32(workgroup_idx / (uniforms.num_total_seq_length_tile * uniforms.num_seq_length_tile));\n" + << "let batch_idx = batch_head_idx / uniforms.num_heads;\n" + << "let qOffset = batch_head_idx * uniforms.M * uniforms.K + m * uniforms.K;\n" << "let sequence_length = uniforms.M;\n" << "var total_sequence_length = uniforms.N;\n"; std::ostringstream oss; InitVarStub(oss, seqlen_k_); shader.MainFunctionBody() << oss.str(); - shader.MainFunctionBody() << "let kOffset = (workgroup_id.z / " << n_reps_ << ") * uniforms.kv_sequence_length * uniforms.K;\n"; + shader.MainFunctionBody() << "let kOffset = (batch_head_idx / uniforms.n_reps) * uniforms.kv_sequence_length * uniforms.K;\n"; if (has_present_key_) { - shader.MainFunctionBody() << "let presentKeyOffset = (workgroup_id.z / " << n_reps_ << ") * uniforms.present_sequence_length * uniforms.K;\n"; + shader.MainFunctionBody() << "let presentKeyOffset = (batch_head_idx / uniforms.n_reps) * uniforms.present_sequence_length * uniforms.K;\n"; } shader.MainFunctionBody() << "var value = f32_val_t(0);\n" "for (var w: u32 = 0u; w < uniforms.K; w += TILE_SIZE) {\n" - " if (global_id.y < uniforms.M && w + local_id.x < uniforms.K) {\n" + " if (m + local_id.y < uniforms.M && w + local_id.x < uniforms.K) {\n" " tileQ[TILE_SIZE * local_id.y + local_id.x] = q[qOffset + local_id.y * uniforms.K + w + local_id.x];\n" " }\n" " if (n + local_id.y < uniforms.N && w + local_id.x < uniforms.K) {\n" @@ -123,7 +124,7 @@ Status AttentionProbsProgram::GenerateShaderCode(ShaderHelper& shader) const { if ((feed_past_key_ && has_present_key_) || (past_present_share_buffer_ && !is_first_prompt_)) { shader.MainFunctionBody() << " if (n + local_id.y < past_sequence_length) {\n" - << " let pastKeyOffset = (workgroup_id.z / " << n_reps_ << ") * uniforms.past_sequence_length * uniforms.K;\n" + << " let pastKeyOffset = (batch_head_idx / uniforms.n_reps) * uniforms.past_sequence_length * uniforms.K;\n" << " tileK[idx] = " << (past_present_share_buffer_ ? "present_key" : "past_key") << "[pastKeyOffset + (n + local_id.y) * uniforms.K + w + local_id.x];\n" << " } else if (n + local_id.y - past_sequence_length < uniforms.kv_sequence_length) {\n" << " tileK[idx] = key[kOffset + (n + local_id.y - past_sequence_length) * uniforms.K + w + local_id.x];\n" @@ -152,9 +153,9 @@ Status AttentionProbsProgram::GenerateShaderCode(ShaderHelper& shader) const { << " workgroupBarrier();\n" << "}\n"; - shader.MainFunctionBody() << "if (global_id.y < uniforms.M && global_id.x < total_sequence_length) {\n" - << " let headOffset = workgroup_id.z * uniforms.M * uniforms.N;\n" - << " let outputIdx = headOffset + global_id.y * uniforms.N + global_id.x;\n" + shader.MainFunctionBody() << "if (m + local_id.y < uniforms.M && n + local_id.x < total_sequence_length) {\n" + << " let headOffset = batch_head_idx * uniforms.M * uniforms.N;\n" + << " let outputIdx = headOffset + m + local_id.y * uniforms.N + n + local_id.x;\n" << " var sum: f32 = " << (components_ == 4 ? "value.x + value.y + value.z + value.w" : (components_ == 2 ? "value.x + value.y" : "value")) << ";\n"; shader.MainFunctionBody() << " output[outputIdx] = output_value_t(sum * uniforms.alpha)"; @@ -181,7 +182,7 @@ Status ComputeAttentionProbs(onnxruntime::webgpu::ComputeContext& context, int o const int components = parameters.head_size_ % 4 == 0 ? 4 : (parameters.head_size_ % 2 == 0 ? 2 : 1); AttentionProbsProgram program{"AttentionProbs", feed_past_key, has_present_key, has_attention_bias, tile_size, - components, parameters.is_first_prompt_, parameters.n_reps, seqlen_k, parameters.past_present_share_buffer_}; + components, parameters.is_first_prompt_, seqlen_k, parameters.past_present_share_buffer_}; program.AddInputs({{Q, ProgramTensorMetadataDependency::TypeAndRank, components}, {K, ProgramTensorMetadataDependency::TypeAndRank, components}}); if (feed_past_key) { @@ -199,9 +200,9 @@ Status ComputeAttentionProbs(onnxruntime::webgpu::ComputeContext& context, int o } const uint32_t vectorized_head_size = (parameters.head_size_ + components - 1) / components; - program.SetDispatchGroupSize((total_sequence_length + tile_size - 1) / tile_size, - (parameters.sequence_length_ + tile_size - 1) / tile_size, - parameters.batch_size_ * parameters.num_heads_) + const uint32_t num_total_seq_length_tile = (total_sequence_length + tile_size - 1) / tile_size; + const uint32_t num_seq_length_tile = (parameters.sequence_length_ + tile_size - 1) / tile_size; + program.SetDispatchGroupSize(parameters.batch_size_ * parameters.num_heads_ * num_seq_length_tile * num_total_seq_length_tile) .SetWorkgroupSize(tile_size, tile_size) .CacheHint(std::to_string(tile_size), parameters.past_present_share_buffer_, feed_past_key, has_present_key, has_attention_bias, seqlen_k != nullptr, components, parameters.is_first_prompt_) .AddUniformVariables({{static_cast(parameters.sequence_length_)}, @@ -214,7 +215,9 @@ Status ComputeAttentionProbs(onnxruntime::webgpu::ComputeContext& context, int o {static_cast(parameters.kv_sequence_length_)}, {static_cast(seqlen_k == nullptr ? total_sequence_length : parameters.seqlen_present_kv_cache_)}, {static_cast(parameters.n_reps)}, - {static_cast(parameters.is_first_prompt_ ? 1 : 0)}}) + {static_cast(parameters.is_first_prompt_ ? 1 : 0)}, + {num_total_seq_length_tile}, + {num_seq_length_tile}}) .SetOverridableConstants({{static_cast(tile_size)}}); return context.RunProgram(program); @@ -228,15 +231,15 @@ Status InPlaceSoftmaxProgram::GenerateShaderCode(ShaderHelper& shader) const { shader.AdditionalImplementation() << "var thread_max: array;\n" << "var thread_sum: array;\n" << "alias f32_val_t = " << (components_ == 4 ? "vec4" : (components_ == 2 ? "vec2" : "f32")) << ";\n"; - shader.MainFunctionBody() << "let batch_idx = workgroup_id.z / uniforms.num_heads;\n" - << "let sequence_length = uniforms.sequence_length;\n" + shader.MainFunctionBody() << "let sequence_length = uniforms.sequence_length;\n" + << "let batch_idx = u32(workgroup_idx / sequence_length) / uniforms.num_heads;\n" << "var total_sequence_length = uniforms.total_sequence_length_comp * " << components_ << ";\n"; std::ostringstream oss; InitVarStub(oss, seqlen_k_); shader.MainFunctionBody() << oss.str() << "let local_offset = local_idx * uniforms.elements_per_thread;\n" - << "let offset = (global_idx / " << work_group_size_ << ") * uniforms.total_sequence_length_comp + local_offset;\n" - << "let seq_causal_length = " << (seqlen_k_ ? "past_sequence_length + workgroup_id.y + 1" : "uniforms.total_sequence_length_comp") << ";\n" + << "let offset = workgroup_idx * uniforms.total_sequence_length_comp + local_offset;\n" + << "let seq_causal_length = " << (seqlen_k_ ? "past_sequence_length + workgroup_idx % sequence_length + 1" : "uniforms.total_sequence_length_comp") << ";\n" << "var thread_max_vector = f32_val_t(-3.402823e+38f);\n" << "for (var i: u32 = 0; i < uniforms.elements_per_thread && i + local_offset < seq_causal_length; i++) {\n" << " thread_max_vector = max(f32_val_t(x[offset + i]), thread_max_vector);\n" @@ -292,7 +295,7 @@ Status ComputeInPlaceSoftmax(onnxruntime::webgpu::ComputeContext& context, Tenso } program.AddOutputs({{probs, ProgramTensorMetadataDependency::TypeAndRank, components}}) .CacheHint(work_group_size) - .SetDispatchGroupSize(1, sequence_length, batch_size * num_heads) + .SetDispatchGroupSize(batch_size * num_heads * sequence_length) .SetWorkgroupSize(work_group_size) .AddUniformVariables({{static_cast(batch_size)}, {static_cast(num_heads)}, @@ -321,19 +324,20 @@ Status VxAttentionScoreProgram::GenerateShaderCode(ShaderHelper& shader) const { shader.AdditionalImplementation() << "var tileQ: array;\n" << "var tileK: array;\n"; - shader.MainFunctionBody() << "let head_idx = workgroup_id.z % uniforms.num_heads;\n" - << "let batch_idx = workgroup_id.z / uniforms.num_heads;\n" - << "let m = global_id.y;\n" - << "let n = global_id.x;\n" - << "let offsetA = workgroup_id.z * (uniforms.M * uniforms.K) + m * uniforms.K;\n" + shader.MainFunctionBody() << "let batch_head_idx = u32(workgroup_idx / (uniforms.num_head_size_tile * uniforms.num_seq_length_tile));\n" + << "let head_idx = batch_head_idx % uniforms.num_heads;\n" + << "let batch_idx = batch_head_idx / uniforms.num_heads;\n" + << "let m = (u32(workgroup_idx / uniforms.num_head_size_tile) % uniforms.num_seq_length_tile) * TILE_SIZE + local_id.y;\n" + << "let n = (workgroup_idx % uniforms.num_head_size_tile) * TILE_SIZE + local_id.x;\n" + << "let offsetA = batch_head_idx * (uniforms.M * uniforms.K) + m * uniforms.K;\n" << "let sequence_length = uniforms.M;\n" << "var total_sequence_length = uniforms.K;\n"; std::ostringstream oss; InitVarStub(oss, seqlen_k_); shader.MainFunctionBody() << oss.str(); - shader.MainFunctionBody() << "let vOffset = (workgroup_id.z / " << n_reps_ << ") * uniforms.N * uniforms.kv_sequence_length + n;\n"; + shader.MainFunctionBody() << "let vOffset = (batch_head_idx / uniforms.n_reps) * uniforms.N * uniforms.kv_sequence_length + n;\n"; if (has_present_value_) { - shader.MainFunctionBody() << "let presentValueOffset = (workgroup_id.z / " << n_reps_ << ") * uniforms.N * uniforms.present_sequence_length + n;\n"; + shader.MainFunctionBody() << "let presentValueOffset = (batch_head_idx / uniforms.n_reps) * uniforms.N * uniforms.present_sequence_length + n;\n"; } shader.MainFunctionBody() << "var value = output_value_t(0);\n" @@ -346,7 +350,7 @@ Status VxAttentionScoreProgram::GenerateShaderCode(ShaderHelper& shader) const { if ((feed_past_value_ && has_present_value_) || (past_present_share_buffer_ && !is_first_prompt_)) { shader.MainFunctionBody() << " if (w + local_id.y < past_sequence_length) {\n" - << " let pastValueOffset = (workgroup_id.z / " << n_reps_ << ") * uniforms.N * uniforms.past_sequence_length + n;\n" + << " let pastValueOffset = (batch_head_idx / uniforms.n_reps) * uniforms.N * uniforms.past_sequence_length + n;\n" << " tileK[idx] = " << (past_present_share_buffer_ ? "present_value" : "past_value") << "[pastValueOffset + (w + local_id.y) * uniforms.N];\n" << " } else if (w + local_id.y - past_sequence_length < uniforms.kv_sequence_length) {\n" << " tileK[idx] = v[vOffset + (w + local_id.y - past_sequence_length) * uniforms.N];\n" @@ -400,7 +404,7 @@ Status ComputeVxAttentionScore(onnxruntime::webgpu::ComputeContext& context, int const int components = parameters.v_head_size_ % 4 == 0 ? 4 : (parameters.v_head_size_ % 2 == 0 ? 2 : 1); constexpr int tile_size = 12; int tile_n_size = tile_size * components; - VxAttentionScoreProgram program{"VxAttentionScore", feed_past_value, has_present_value, tile_size, parameters.is_first_prompt_, parameters.n_reps, seqlen_k, parameters.past_present_share_buffer_}; + VxAttentionScoreProgram program{"VxAttentionScore", feed_past_value, has_present_value, tile_size, parameters.is_first_prompt_, seqlen_k, parameters.past_present_share_buffer_}; program.AddInputs({{probs, ProgramTensorMetadataDependency::TypeAndRank}, {V, ProgramTensorMetadataDependency::TypeAndRank, components}}); if (feed_past_value) { @@ -414,9 +418,9 @@ Status ComputeVxAttentionScore(onnxruntime::webgpu::ComputeContext& context, int program.AddOutput({present_value, ProgramTensorMetadataDependency::TypeAndRank, components}); } - program.SetDispatchGroupSize((parameters.v_head_size_ + tile_n_size - 1) / tile_n_size, - (parameters.sequence_length_ + tile_size - 1) / tile_size, - parameters.batch_size_ * parameters.num_heads_) + const uint32_t num_head_size_tile = (parameters.v_head_size_ + tile_n_size - 1) / tile_n_size; + const uint32_t num_seq_length_tile = (parameters.sequence_length_ + tile_size - 1) / tile_size; + program.SetDispatchGroupSize(parameters.batch_size_ * parameters.num_heads_ * num_head_size_tile * num_seq_length_tile) .CacheHint(std::to_string(tile_size), parameters.past_present_share_buffer_, feed_past_value, has_present_value, seqlen_k != nullptr, parameters.is_first_prompt_) .SetWorkgroupSize(tile_size, tile_size) .AddUniformVariables({{static_cast(parameters.sequence_length_)}, @@ -429,7 +433,9 @@ Status ComputeVxAttentionScore(onnxruntime::webgpu::ComputeContext& context, int {static_cast(parameters.kv_sequence_length_)}, {static_cast(seqlen_k == nullptr ? total_sequence_length : parameters.seqlen_present_kv_cache_)}, {static_cast(parameters.n_reps)}, - {static_cast(parameters.is_first_prompt_)}}) + {static_cast(parameters.is_first_prompt_)}, + {num_head_size_tile}, + {num_seq_length_tile}}) .SetOverridableConstants({{static_cast(tile_size)}}); return context.RunProgram(program); diff --git a/onnxruntime/contrib_ops/webgpu/bert/attention.h b/onnxruntime/contrib_ops/webgpu/bert/attention.h index 164ea72b07d9d..7c0cb40cc7f93 100644 --- a/onnxruntime/contrib_ops/webgpu/bert/attention.h +++ b/onnxruntime/contrib_ops/webgpu/bert/attention.h @@ -34,8 +34,8 @@ class TransferBSDToBNSHProgram final : public Program class AttentionProbsProgram final : public Program { public: AttentionProbsProgram(const std::string& kernel_name, bool feed_past_key, bool has_present_key, - bool has_attention_bias, int tile_size, int components, bool is_first_prompt, int n_reps = 1, const Tensor* seqlen_k = nullptr, bool past_present_share_buffer = false) - : Program{kernel_name}, feed_past_key_(feed_past_key), has_present_key_(has_present_key), has_attention_bias_(has_attention_bias), tile_size_(tile_size), components_(components), n_reps_(n_reps), seqlen_k_(seqlen_k), past_present_share_buffer_(past_present_share_buffer), is_first_prompt_(is_first_prompt) { + bool has_attention_bias, int tile_size, int components, bool is_first_prompt, const Tensor* seqlen_k = nullptr, bool past_present_share_buffer = false) + : Program{kernel_name}, feed_past_key_(feed_past_key), has_present_key_(has_present_key), has_attention_bias_(has_attention_bias), tile_size_(tile_size), components_(components), seqlen_k_(seqlen_k), past_present_share_buffer_(past_present_share_buffer), is_first_prompt_(is_first_prompt) { } Status GenerateShaderCode(ShaderHelper& sh) const override; @@ -50,7 +50,9 @@ class AttentionProbsProgram final : public Program { {"kv_sequence_length", ProgramUniformVariableDataType::Uint32}, {"present_sequence_length", ProgramUniformVariableDataType::Uint32}, {"n_reps", ProgramUniformVariableDataType::Uint32}, - {"is_first_prompt", ProgramUniformVariableDataType::Uint32}); + {"is_first_prompt", ProgramUniformVariableDataType::Uint32}, + {"num_total_seq_length_tile", ProgramUniformVariableDataType::Uint32}, + {"num_seq_length_tile", ProgramUniformVariableDataType::Uint32}); WEBGPU_PROGRAM_DEFINE_OVERRIDABLE_CONSTANTS({"TILE_SIZE", ProgramConstantDataType::Uint32}); @@ -60,7 +62,6 @@ class AttentionProbsProgram final : public Program { bool has_attention_bias_; int tile_size_; int components_; - int n_reps_; const Tensor* seqlen_k_; bool past_present_share_buffer_; bool is_first_prompt_; @@ -90,8 +91,8 @@ class InPlaceSoftmaxProgram final : public Program { class VxAttentionScoreProgram final : public Program { public: - VxAttentionScoreProgram(const std::string& kernel_name, bool feed_past_value, bool has_present_value, int tile_size, bool is_first_prompt, int n_reps = 1, const Tensor* seqlen_k = nullptr, bool past_present_share_buffer = false) - : Program{kernel_name}, feed_past_value_(feed_past_value), has_present_value_(has_present_value), tile_size_(tile_size), n_reps_(n_reps), seqlen_k_(seqlen_k), past_present_share_buffer_(past_present_share_buffer), is_first_prompt_(is_first_prompt) { + VxAttentionScoreProgram(const std::string& kernel_name, bool feed_past_value, bool has_present_value, int tile_size, bool is_first_prompt, const Tensor* seqlen_k = nullptr, bool past_present_share_buffer = false) + : Program{kernel_name}, feed_past_value_(feed_past_value), has_present_value_(has_present_value), tile_size_(tile_size), seqlen_k_(seqlen_k), past_present_share_buffer_(past_present_share_buffer), is_first_prompt_(is_first_prompt) { } Status GenerateShaderCode(ShaderHelper& sh) const override; @@ -106,7 +107,9 @@ class VxAttentionScoreProgram final : public Program { {"kv_sequence_length", ProgramUniformVariableDataType::Uint32}, {"present_sequence_length", ProgramUniformVariableDataType::Uint32}, {"n_reps", ProgramUniformVariableDataType::Uint32}, - {"is_first_prompt", ProgramUniformVariableDataType::Uint32}); + {"is_first_prompt", ProgramUniformVariableDataType::Uint32}, + {"num_head_size_tile", ProgramUniformVariableDataType::Uint32}, + {"num_seq_length_tile", ProgramUniformVariableDataType::Uint32}); WEBGPU_PROGRAM_DEFINE_OVERRIDABLE_CONSTANTS({"TILE_SIZE", ProgramConstantDataType::Uint32}); @@ -114,7 +117,6 @@ class VxAttentionScoreProgram final : public Program { bool feed_past_value_; bool has_present_value_; int tile_size_; - int n_reps_; const Tensor* seqlen_k_; bool past_present_share_buffer_; bool is_first_prompt_; diff --git a/onnxruntime/contrib_ops/webgpu/bert/attention_common.h b/onnxruntime/contrib_ops/webgpu/bert/attention_common.h index be80ade8b87d0..06b9c88ce8993 100644 --- a/onnxruntime/contrib_ops/webgpu/bert/attention_common.h +++ b/onnxruntime/contrib_ops/webgpu/bert/attention_common.h @@ -7,9 +7,9 @@ #include "core/providers/webgpu/program.h" #include "core/providers/webgpu/shader_helper.h" #include "core/providers/webgpu/webgpu_kernel.h" -#include "contrib_ops/webgpu/bert/attention_common.h" -#include "contrib_ops/cpu/bert/attention_common.h" +#include "contrib_ops/cpu/bert/attention_parameters.h" + namespace onnxruntime { namespace contrib { namespace webgpu { diff --git a/onnxruntime/contrib_ops/webgpu/bert/bias_add.cc b/onnxruntime/contrib_ops/webgpu/bert/bias_add.cc new file mode 100644 index 0000000000000..0f2e6d725007f --- /dev/null +++ b/onnxruntime/contrib_ops/webgpu/bert/bias_add.cc @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/webgpu_utils.h" +#include "core/providers/webgpu/webgpu_supported_types.h" +#include "contrib_ops/webgpu/bert/bias_add.h" +#include "contrib_ops/webgpu/webgpu_contrib_kernels.h" + +namespace onnxruntime { +namespace contrib { +namespace webgpu { + +ONNX_OPERATOR_KERNEL_EX( + BiasAdd, + kMSDomain, + 1, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T", WebGpuSupportedFloatTypes()), + BiasAdd); + +Status BiasAddProgram::GenerateShaderCode(ShaderHelper& shader) const { + const ShaderVariableHelper& input = shader.AddInput("input", ShaderUsage::UseUniform); + const ShaderVariableHelper& bias = shader.AddInput("bias", ShaderUsage::UseUniform); + const ShaderVariableHelper& residual = shader.AddInput("residual", ShaderUsage::UseUniform); + const ShaderVariableHelper& output = shader.AddOutput("output", ShaderUsage::UseUniform); + + shader.MainFunctionBody() << shader.GuardAgainstOutOfBoundsWorkgroupSizes("uniforms.output_size") + << " let value = " << input.GetByOffset("global_idx") + << " + " << bias.GetByOffset("global_idx % uniforms.channels") + << " + " << residual.GetByOffset("global_idx") << ";\n" + << " " + output.SetByOffset("global_idx", "value"); + + return Status::OK(); +} + +Status BiasAdd::ComputeInternal(onnxruntime::webgpu::ComputeContext& context) const { + const auto* input = context.Input(0); + const auto* bias = context.Input(1); + const auto* residual = context.Input(2); + + TensorShape input_shape = input->Shape(); + + if (input_shape.NumDimensions() != 3) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "BiasAdd input should have 3 dimensions."); + } + + int64_t channels = input_shape[2]; + TensorShape bias_shape = bias->Shape(); + if (bias_shape.NumDimensions() != 1 || bias_shape[0] != channels) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "BiasAdd bias should have 1 dimension with size equal to the number of channels."); + } + + int components = GetMaxComponents(channels); + channels /= components; + + auto* output = context.Output(0, input_shape); + int64_t output_size = output->Shape().Size() / components; + + BiasAddProgram program{}; + program + .AddInputs({{input, ProgramTensorMetadataDependency::None, components}, + {bias, ProgramTensorMetadataDependency::None, components}, + {residual, ProgramTensorMetadataDependency::None, components}}) + .AddOutput({output, ProgramTensorMetadataDependency::None, components}) + .SetDispatchGroupSize((output_size + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE) + .AddUniformVariables({{static_cast(output_size)}, {static_cast(channels)}}); + return context.RunProgram(program); +} + +} // namespace webgpu +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/webgpu/bert/bias_add.h b/onnxruntime/contrib_ops/webgpu/bert/bias_add.h new file mode 100644 index 0000000000000..58cc5f09f8003 --- /dev/null +++ b/onnxruntime/contrib_ops/webgpu/bert/bias_add.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/webgpu/program.h" +#include "core/providers/webgpu/webgpu_kernel.h" + +namespace onnxruntime { +namespace contrib { +namespace webgpu { + +using namespace onnxruntime::webgpu; +using onnxruntime::webgpu::ComputeContext; + +class BiasAddProgram final : public Program { + public: + BiasAddProgram() : Program{"BiasAdd"} {} + Status GenerateShaderCode(ShaderHelper& sh) const override; + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"output_size", ProgramUniformVariableDataType::Uint32}, + {"channels", ProgramUniformVariableDataType::Uint32}); +}; + +class BiasAdd final : public WebGpuKernel { + public: + BiasAdd(const OpKernelInfo& info) : WebGpuKernel(info) {} + Status ComputeInternal(ComputeContext& context) const override; +}; + +} // namespace webgpu +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/webgpu/bert/bias_split_gelu.cc b/onnxruntime/contrib_ops/webgpu/bert/bias_split_gelu.cc new file mode 100644 index 0000000000000..4656fc486fccf --- /dev/null +++ b/onnxruntime/contrib_ops/webgpu/bert/bias_split_gelu.cc @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/webgpu_supported_types.h" +#include "contrib_ops/webgpu/bert/bias_split_gelu.h" +#include "contrib_ops/webgpu/webgpu_contrib_kernels.h" +#include "core/providers/webgpu/webgpu_utils.h" +#include "core/providers/webgpu/math/unary_elementwise_ops.h" + +namespace onnxruntime { +namespace contrib { +namespace webgpu { + +ONNX_OPERATOR_KERNEL_EX( + BiasSplitGelu, + kMSDomain, + 1, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T", WebGpuSupportedFloatTypes()), + BiasSplitGelu); + +Status BiasSplitGeluProgram::GenerateShaderCode(ShaderHelper& shader) const { + const ShaderVariableHelper& x = + shader.AddInput("x", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias); + const ShaderVariableHelper& bias = shader.AddInput("bias", ShaderUsage::UseUniform); + const ShaderVariableHelper& output = shader.AddOutput("output", ShaderUsage::UseUniform); + + shader.AdditionalImplementation() << ErfImpl; + + shader.MainFunctionBody() << shader.GuardAgainstOutOfBoundsWorkgroupSizes("uniforms.output_size") + << "const M_SQRT2: f32 = sqrt(2.0);\n" + << "let halfChannels = uniforms.channels / 2u;\n" + << "let biasIdx = global_idx % halfChannels;\n" + << "let batchIndex = global_idx / halfChannels;\n" + << "let inputOffset = biasIdx + batchIndex * halfChannels * 2;\n" + << "let valueLeft = " << x.GetByOffset("inputOffset") << " + " << bias.GetByOffset("biasIdx") << ";\n" + << "let valueRight = " << x.GetByOffset("inputOffset + halfChannels") << " + " << bias.GetByOffset("biasIdx + halfChannels") << ";\n" + << "let geluRight = valueRight * 0.5 * (erf_v(valueRight / M_SQRT2) + 1);\n" + << output.SetByOffset("global_idx", "valueLeft * geluRight"); + + return Status::OK(); +} + +Status BiasSplitGelu::ComputeInternal(onnxruntime::webgpu::ComputeContext& context) const { + const auto* input = context.Input(0); + const auto* bias = context.Input(1); + + TensorShape input_shape = input->Shape(); + + if (input_shape.NumDimensions() != 3) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "BiasSplitGelu input should have 3 dimensions."); + } + + int64_t channels = input_shape[2]; + input_shape[2] = channels / 2; // for output shape calculation (N,S,D) -> (N,S,D/2) + + TensorShape bias_shape = bias->Shape(); + if (bias_shape.NumDimensions() != 1 || bias_shape[0] != channels) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "BiasSplitGelu bias should have 1 dimension with size equal to the number of channels."); + } + + int components = GetMaxComponents(channels); + channels /= components; + + auto* output = context.Output(0, input_shape); + int64_t output_size = output->Shape().Size() / components; + + BiasSplitGeluProgram program{}; + program + .AddInputs({{input, ProgramTensorMetadataDependency::None, components}, + {bias, ProgramTensorMetadataDependency::None, components}}) + .AddOutput({output, ProgramTensorMetadataDependency::None, components}) + .SetDispatchGroupSize((output_size + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE) + .AddUniformVariables({{static_cast(output_size)}, {static_cast(channels)}}); + return context.RunProgram(program); +} + +} // namespace webgpu +} // namespace contrib +} // namespace onnxruntime \ No newline at end of file diff --git a/onnxruntime/contrib_ops/webgpu/bert/bias_split_gelu.h b/onnxruntime/contrib_ops/webgpu/bert/bias_split_gelu.h new file mode 100644 index 0000000000000..ccc3dd8c89b7b --- /dev/null +++ b/onnxruntime/contrib_ops/webgpu/bert/bias_split_gelu.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/webgpu/program.h" +#include "core/providers/webgpu/webgpu_kernel.h" + +namespace onnxruntime { +namespace contrib { +namespace webgpu { + +using namespace onnxruntime::webgpu; +using onnxruntime::webgpu::ComputeContext; + +class BiasSplitGeluProgram final : public Program { + public: + BiasSplitGeluProgram() : Program{"BiasSplitGelu"} {} + Status GenerateShaderCode(ShaderHelper& sh) const override; + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"output_size", ProgramUniformVariableDataType::Uint32}, + {"channels", ProgramUniformVariableDataType::Uint32}); +}; + +class BiasSplitGelu final : public WebGpuKernel { + public: + BiasSplitGelu(const OpKernelInfo& info) : WebGpuKernel(info) {} + Status ComputeInternal(ComputeContext& context) const override; +}; + +} // namespace webgpu +} // namespace contrib +} // namespace onnxruntime \ No newline at end of file diff --git a/onnxruntime/contrib_ops/webgpu/bert/fast_gelu.cc b/onnxruntime/contrib_ops/webgpu/bert/fast_gelu.cc index a5cae7e7f6747..29ea4f81dd5e1 100644 --- a/onnxruntime/contrib_ops/webgpu/bert/fast_gelu.cc +++ b/onnxruntime/contrib_ops/webgpu/bert/fast_gelu.cc @@ -50,7 +50,7 @@ Status FastGelu::ComputeInternal(onnxruntime::webgpu::ComputeContext& context) c const auto* bias = context.Input(1); auto* output = context.Output(0, input->Shape()); - uint32_t data_size = gsl::narrow(output->Shape().Size()); + uint32_t data_size = onnxruntime::narrow(output->Shape().Size()); if (data_size == 0) { return Status::OK(); } @@ -60,7 +60,7 @@ Status FastGelu::ComputeInternal(onnxruntime::webgpu::ComputeContext& context) c int bias_components = 1; if (bias != nullptr) { - bias_size = gsl::narrow(bias->Shape().Size()); + bias_size = onnxruntime::narrow(bias->Shape().Size()); if (bias_size % 4 == 0) { bias_components = 4; bias_size = bias_size / 4; diff --git a/onnxruntime/contrib_ops/webgpu/bert/flash_attention.cc b/onnxruntime/contrib_ops/webgpu/bert/flash_attention.cc index b51c2fbe27e1d..bb5de40eb27c5 100644 --- a/onnxruntime/contrib_ops/webgpu/bert/flash_attention.cc +++ b/onnxruntime/contrib_ops/webgpu/bert/flash_attention.cc @@ -26,73 +26,88 @@ Status CopyKVCacheProgram::GenerateShaderCode(ShaderHelper& shader) const { // H - head size or hidden dimension for each qkv head. // KV cache is stored as BN(total_sequence_length)H // Attention bias is in BN(total_sequence_length) - shader.AddInput("key", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias); - shader.AddInput("value", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias); + const auto& key = shader.AddInput("key", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias | ShaderUsage::UseIndicesTypeAlias); + shader.AddInput("value", ShaderUsage::UseUniform); + const auto& present_key = shader.AddOutput("present_key", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias); + const auto& present_value = shader.AddOutput("present_value", ShaderUsage::UseUniform); + const auto& copy_kv_shape = shader.AddIndices("copy_kv_shape"); + + shader.MainFunctionBody() << shader.GuardAgainstOutOfBoundsWorkgroupSizes("uniforms.copy_size") + << " let output_indices = " << copy_kv_shape.OffsetToIndices("global_idx") << ";\n" + << " let head_size_id = output_indices[3];\n" + " let sequence_id = output_indices[2];\n" + " let num_head_id = output_indices[1];\n" + " let batch = output_indices[0];\n"; if (has_past_) { - shader.AddInput("past_key", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias); - shader.AddInput("past_value", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias); - } - shader.AddOutput("present_key", ShaderUsage::UseUniform); - shader.AddOutput("present_value", ShaderUsage::UseUniform); - - shader.MainFunctionBody() << "let headIdx = workgroup_id.z;\n" - << "let kIdx = workgroup_id.x;\n" - << "let presentKeyOffset = headIdx * num_workgroups.x * uniforms.vectorized_head_size + (kIdx)*uniforms.vectorized_head_size;\n"; - if (has_past_) { - shader.MainFunctionBody() << "if (kIdx < uniforms.past_sequence_length) {\n" - << " let pastKeyOffset = headIdx * uniforms.past_sequence_length * uniforms.vectorized_head_size + (kIdx)*uniforms.vectorized_head_size;\n" - << " for (var w: u32 = 0u; w < uniforms.vectorized_head_size; w ++) {\n" - << " present_key[presentKeyOffset+w] = past_key[pastKeyOffset+w];\n" - << " present_value[presentKeyOffset+w] = past_value[pastKeyOffset+w];\n" - << " }\n" - << "}\n" - << "else if (kIdx >= uniforms.past_sequence_length) {\n"; + shader.MainFunctionBody() << "let past_sequence_length = uniforms.past_sequence_length;\n"; + if (past_present_share_buffer_) { + shader.MainFunctionBody() << " let present_offset = " << present_key.IndicesToOffset("present_key_indices_t(batch, num_head_id, past_sequence_length + sequence_id, head_size_id)") << ";\n" + << " let offset = " << key.IndicesToOffset(kv_BNSH_ ? "key_indices_t(batch, num_head_id, sequence_id, head_size_id)" : "key_indices_t(batch, sequence_id, num_head_id, head_size_id)") << ";\n" + << " " << present_key.SetByOffset("present_offset", "key[offset]") << ";\n" + << " " << present_value.SetByOffset("present_offset", "value[offset]") << ";\n"; + } else { + const auto& past_key = shader.AddInput("past_key", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias | ShaderUsage::UseIndicesTypeAlias); + shader.AddInput("past_value", ShaderUsage::UseUniform); + shader.MainFunctionBody() << "let present_offset = global_idx;" + << "if (sequence_id < past_sequence_length) {\n" + << " let pastOffset = " << past_key.IndicesToOffset("past_key_indices_t(batch, num_head_id, sequence_id, head_size_id)") << ";\n" + << " " << present_key.SetByOffset("present_offset", "past_key[pastOffset]") << ";\n" + << " " << present_value.SetByOffset("present_offset", "past_value[pastOffset]") << ";\n" + << "} else {\n" + << " let offset = " << key.IndicesToOffset(kv_BNSH_ ? "key_indices_t(batch, num_head_id, sequence_id - past_sequence_length, head_size_id)" : "key_indices_t(batch, sequence_id - past_sequence_length, num_head_id, head_size_id)") << ";\n" + << " " << present_key.SetByOffset("present_offset", "key[offset]") << ";\n" + << " " << present_value.SetByOffset("present_offset", "value[offset]") << ";\n" + << "}"; + } } else { - shader.MainFunctionBody() << "if (kIdx >= uniforms.past_sequence_length) {\n"; + shader.MainFunctionBody() << " let present_offset = " << (past_present_share_buffer_ ? present_key.IndicesToOffset("output_indices") : "global_idx") << ";\n" + << "let offset = " << key.IndicesToOffset(kv_BNSH_ ? "key_indices_t(batch, num_head_id, sequence_id, head_size_id)" : "key_indices_t(batch, sequence_id, num_head_id, head_size_id)") << ";\n" + << present_key.SetByOffset("present_offset", "key[offset]") << ";\n" + << present_value.SetByOffset("present_offset", "value[offset]") << ";\n"; } - shader.MainFunctionBody() << " let nkIdx = kIdx - uniforms.past_sequence_length;\n" - << " // Assumes kv have BSNH layout. num_workgroups.z is the num_head as per the dispatch requirement.\n" - << " let nOffset = nkIdx * uniforms.vectorized_head_size * num_workgroups.z + headIdx*uniforms.vectorized_head_size;\n" - << " // Assumes kv have BNSH layout.\n" - << " // let nOffset = headIdx * uniforms.kv_sequence_length * uniforms.vectorized_head_size + nkIdx * uniforms.vectorized_head_size;\n" - << " for (var w: u32 = 0u; w < uniforms.vectorized_head_size; w ++) {\n" - << " present_key[presentKeyOffset+w] = key[nOffset+w];\n" - << " present_value[presentKeyOffset+w] = value[nOffset+w];\n" - << " }\n" - << "}\n"; - return Status::OK(); } Status CopyKVCache(onnxruntime::webgpu::ComputeContext& context, const WebgpuAttentionParameters& parameters, const Tensor* K, const Tensor* past_key, Tensor* present_key, - const Tensor* V, const Tensor* past_value, Tensor* present_value, - int past_sequence_length, int total_sequence_length) { + const Tensor* V, const Tensor* past_value, Tensor* present_value) { // CopyKVCache takes past key/value and current key/value and copies them to present key and value. // This makes it so that FlashAttention only needs to look at present key and value, and saves // number of input buffers in the shader, which we run out of (<=8) without this optimization. const int components = parameters.head_size_ % 4 == 0 ? 4 : (parameters.head_size_ % 2 == 0 ? 2 : 1); - bool has_past = (past_sequence_length != 0); - CopyKVCacheProgram program{"CopyKVCache", has_past}; - if (has_past) { - program.AddInputs({{K, ProgramTensorMetadataDependency::TypeAndRank, components}, - {V, ProgramTensorMetadataDependency::TypeAndRank, components}, - {past_key, ProgramTensorMetadataDependency::TypeAndRank, components}, - {past_value, ProgramTensorMetadataDependency::TypeAndRank, components}}); - } else { + bool has_past = (parameters.total_sequence_length_ - parameters.kv_sequence_length_) > 0; + // parameters.total_sequence_length_ is past_sequence_length + kv_sequence_length. + // parameters.kv_num_heads_ may be smaller than parameters.num_heads_ when parameters.is_gqa_ is true. + int num_heads = parameters.is_gqa_ ? parameters.kv_num_heads_ : parameters.num_heads_; + // Only copy the new kv data for static kv cache + int copy_sequence_length = has_past && parameters.past_present_share_buffer_ ? parameters.kv_sequence_length_ : parameters.total_sequence_length_; + TensorShape copy_kv_shape{parameters.batch_size_, num_heads, copy_sequence_length, parameters.head_size_ / components}; + int64_t copy_size = copy_kv_shape.Size(); + CopyKVCacheProgram program{"CopyKVCache", has_past, parameters.qkv_format_ == Q_K_V_BSNH_BNSH_BNSH, parameters.past_present_share_buffer_}; + if (parameters.qkv_format_ == Q_K_V_BSNH_BNSH_BNSH) { program.AddInputs({{K, ProgramTensorMetadataDependency::TypeAndRank, components}, {V, ProgramTensorMetadataDependency::TypeAndRank, components}}); + } else { + ORT_ENFORCE(parameters.qkv_format_ == Q_K_V_BSNH, "qkv format ", parameters.qkv_format_, " is not supported yet in CopyKVCache."); + // Reshape (batch_size, kv_sequence_length, kv_hidden_size) to (batch_size, kv_sequence_length, num_head, head_size) + TensorShape reshaped_KV_shape{parameters.batch_size_, parameters.kv_sequence_length_, num_heads, parameters.head_size_ / components}; + program.AddInputs({{K, ProgramTensorMetadataDependency::TypeAndRank, reshaped_KV_shape, components}, + {V, ProgramTensorMetadataDependency::TypeAndRank, reshaped_KV_shape, components}}); + } + if (has_past && !parameters.past_present_share_buffer_) { + program.AddInputs({{past_key, ProgramTensorMetadataDependency::TypeAndRank, components}, + {past_value, ProgramTensorMetadataDependency::TypeAndRank, components}}); } - program.AddOutputs({{present_key, ProgramTensorMetadataDependency::Rank, components}, - {present_value, ProgramTensorMetadataDependency::Rank, components}}); - - program.SetDispatchGroupSize(total_sequence_length, 1, parameters.num_heads_) - .SetWorkgroupSize(1) - .CacheHint(std::to_string(components) + std::to_string(has_past)) - .AddUniformVariables({{static_cast(past_sequence_length)}, - {static_cast(parameters.kv_sequence_length_)}, - {static_cast(parameters.head_size_ / components)}}); + {present_value, ProgramTensorMetadataDependency::Rank, components}}) + .AddIndices(std::move(copy_kv_shape)); + program.SetDispatchGroupSize(static_cast((copy_size + 63) / 64)) + .SetWorkgroupSize(64) + .CacheHint(has_past, parameters.qkv_format_, parameters.past_present_share_buffer_) + .AddUniformVariables({{static_cast(copy_size)}, + // Note that when parameters.past_present_share_buffer_ is true, parameters.past_sequence_length_ will become to + // max_sequence_length. To get a valid past_sequence_length, we use total_sequence_length - kv_sequence_length. + {static_cast(parameters.total_sequence_length_ - parameters.kv_sequence_length_)}}); return context.RunProgram(program); } @@ -156,7 +171,7 @@ Status FlashAttentionProgram::GenerateShaderCode(ShaderHelper& shader) const { for (var idx:u32 = local_idx; idx < qkv_head_size_vec*k_step; idx+=workgroup_size_x) { let slot = u32(idx/qkv_head_size_vec); - let val = select(q_value_t(0), present_key[offset+idx], k_start + slot < uniforms.present_sequence_length); + let val = select(q_value_t(0), present_key[offset+idx], k_start + slot < uniforms.total_sequence_length); k_tile[slot][idx%qkv_head_size_vec] = val; } } @@ -167,7 +182,7 @@ Status FlashAttentionProgram::GenerateShaderCode(ShaderHelper& shader) const { for (var idx:u32 = local_idx; idx < qkv_head_size_vec*k_step; idx+=workgroup_size_x) { let slot = u32(idx/qkv_head_size_vec); - let val = select(q_value_t(0), present_value[offset+idx], v_start + slot < uniforms.present_sequence_length); + let val = select(q_value_t(0), present_value[offset+idx], v_start + slot < uniforms.total_sequence_length); v_tile[slot][idx%qkv_head_size_vec] = val; } } @@ -187,12 +202,12 @@ Status FlashAttentionProgram::GenerateShaderCode(ShaderHelper& shader) const { fn loadAttentionBias(q_idx_global : u32, k_idx_global : u32, head_idx: u32) -> vec4 { // Stored as float16[batch_size,num_heads,new_seq_length,total_sequence_length] - if (q_idx_global >= uniforms.new_sequence_length || k_idx_global >= uniforms.present_sequence_length) { + if (q_idx_global >= uniforms.new_sequence_length || k_idx_global >= uniforms.total_sequence_length) { return vec4(0); } - let offset_base = head_idx * uniforms.new_sequence_length * uniforms.present_sequence_length + q_idx_global * uniforms.present_sequence_length; + let offset_base = head_idx * uniforms.new_sequence_length * uniforms.total_sequence_length + q_idx_global * uniforms.total_sequence_length; let offset = offset_base + k_idx_global; - let offset_max = offset_base + uniforms.present_sequence_length; + let offset_max = offset_base + uniforms.total_sequence_length; let c1 = q_element_t(attention_bias[min(offset, offset_max)]); let c2 = q_element_t(attention_bias[min(offset+1, offset_max)]); let c3 = q_element_t(attention_bias[min(offset+2, offset_max)]); @@ -212,12 +227,12 @@ Status FlashAttentionProgram::GenerateShaderCode(ShaderHelper& shader) const { // Shader is designed to be dispatched as Dispatch(num_heads, new_sequence_length / workgroup_size_x, 1) // Each lane/thread is responsible for a single q. shader.MainFunctionBody() << R"MAIN_FN( - let head_idx = workgroup_id.x; + let head_idx = u32(workgroup_idx / uniforms.num_seq_tile); let capped_sg_id = min(sg_id, max_k_step); let capped_sg_size = min(sg_size, max_k_step); // Load Q - let q_idx_global = workgroup_id.y * workgroup_size_x + local_idx; + let q_idx_global = (workgroup_idx % uniforms.num_seq_tile) * workgroup_size_x + local_idx; let valid_q = q_idx_global < uniforms.new_sequence_length; if (valid_q) { @@ -227,11 +242,11 @@ Status FlashAttentionProgram::GenerateShaderCode(ShaderHelper& shader) const { var previous_max : q_element_t = min_value; var previous_denom : q_element_t = 0; - for(var k_start = 0u; k_start < uniforms.present_sequence_length; k_start+=capped_sg_size) + for(var k_start = 0u; k_start < uniforms.total_sequence_length; k_start+=capped_sg_size) { workgroupBarrier(); - loadk(k_start, head_idx, local_idx, capped_sg_size); - loadv(k_start, head_idx, local_idx, capped_sg_size); + loadk(k_start, head_idx / uniforms.n_reps, local_idx, capped_sg_size); + loadv(k_start, head_idx / uniforms.n_reps, local_idx, capped_sg_size); workgroupBarrier(); // Compute QKt @@ -288,24 +303,26 @@ Status FlashAttentionProgram::GenerateShaderCode(ShaderHelper& shader) const { qk_4 = qk_4 * q_element_t(uniforms.alpha) + loadAttentionBias(q_idx_global, k_start+12, head_idx); } + let seq_causal_length = select(uniforms.total_sequence_length, uniforms.past_sequence_length + q_idx_global + 1, uniforms.is_gqa > 0); // Neuter qk values where K is out of bounds. - qk_1[1] = select(min_value, qk_1[1], k_start+1 < uniforms.present_sequence_length); - qk_1[2] = select(min_value, qk_1[2], k_start+2 < uniforms.present_sequence_length); - qk_1[3] = select(min_value, qk_1[3], k_start+3 < uniforms.present_sequence_length); - qk_2[0] = select(min_value, qk_2[0], k_start+4 < uniforms.present_sequence_length); - qk_2[1] = select(min_value, qk_2[1], k_start+5 < uniforms.present_sequence_length); - qk_2[2] = select(min_value, qk_2[2], k_start+6 < uniforms.present_sequence_length); - qk_2[3] = select(min_value, qk_2[3], k_start+7 < uniforms.present_sequence_length); + qk_1[0] = select(min_value, qk_1[0], k_start+0 < seq_causal_length); + qk_1[1] = select(min_value, qk_1[1], k_start+1 < seq_causal_length); + qk_1[2] = select(min_value, qk_1[2], k_start+2 < seq_causal_length); + qk_1[3] = select(min_value, qk_1[3], k_start+3 < seq_causal_length); + qk_2[0] = select(min_value, qk_2[0], k_start+4 < seq_causal_length); + qk_2[1] = select(min_value, qk_2[1], k_start+5 < seq_causal_length); + qk_2[2] = select(min_value, qk_2[2], k_start+6 < seq_causal_length); + qk_2[3] = select(min_value, qk_2[3], k_start+7 < seq_causal_length); if (sg_size > 8) { - qk_3[0] = select(min_value, qk_3[0], k_start+8 < uniforms.present_sequence_length); - qk_3[1] = select(min_value, qk_3[1], k_start+9 < uniforms.present_sequence_length); - qk_3[2] = select(min_value, qk_3[2], k_start+10 < uniforms.present_sequence_length); - qk_3[3] = select(min_value, qk_3[3], k_start+11 < uniforms.present_sequence_length); - qk_4[0] = select(min_value, qk_4[0], k_start+12 < uniforms.present_sequence_length); - qk_4[1] = select(min_value, qk_4[1], k_start+13 < uniforms.present_sequence_length); - qk_4[2] = select(min_value, qk_4[2], k_start+14 < uniforms.present_sequence_length); - qk_4[3] = select(min_value, qk_4[3], k_start+15 < uniforms.present_sequence_length); + qk_3[0] = select(min_value, qk_3[0], k_start+8 < seq_causal_length); + qk_3[1] = select(min_value, qk_3[1], k_start+9 < seq_causal_length); + qk_3[2] = select(min_value, qk_3[2], k_start+10 < seq_causal_length); + qk_3[3] = select(min_value, qk_3[3], k_start+11 < seq_causal_length); + qk_4[0] = select(min_value, qk_4[0], k_start+12 < seq_causal_length); + qk_4[1] = select(min_value, qk_4[1], k_start+13 < seq_causal_length); + qk_4[2] = select(min_value, qk_4[2], k_start+14 < seq_causal_length); + qk_4[3] = select(min_value, qk_4[3], k_start+15 < seq_causal_length); } // @@ -347,6 +364,7 @@ Status FlashAttentionProgram::GenerateShaderCode(ShaderHelper& shader) const { } let sum_vec = qk_1 + qk_2 + qk_3 + qk_4; let sum = sum_vec.x + sum_vec.y + sum_vec.z + sum_vec.w; + // Compute lhs term of update di prime and the compute di prime. let dleft = previous_denom * exp(previous_max-new_max); var d = dleft + sum; @@ -364,7 +382,7 @@ Status FlashAttentionProgram::GenerateShaderCode(ShaderHelper& shader) const { if (sg_size > 8) { for (var i:u32 = 0; i < qkv_head_size_vec; i++) { - var val = select(vec4(0), v_tile[capped_sg_id][i], k_start + capped_sg_id < uniforms.present_sequence_length); + var val = v_tile[capped_sg_id][i]; var sum = subgroupShuffle(val, 0) * qk_1[0]; sum += subgroupShuffle(val, 1) * qk_1[1]; sum += subgroupShuffle(val, 2) * qk_1[2]; @@ -388,7 +406,7 @@ Status FlashAttentionProgram::GenerateShaderCode(ShaderHelper& shader) const { { for (var i:u32 = 0; i < qkv_head_size_vec; i++) { - var val = select(vec4(0), v_tile[capped_sg_id][i], k_start + capped_sg_id < uniforms.present_sequence_length); + var val = select(vec4(0), v_tile[capped_sg_id][i], k_start + capped_sg_id < seq_causal_length); var sum = subgroupShuffle(val, 0) * qk_1[0]; sum += subgroupShuffle(val, 1) * qk_1[1]; sum += subgroupShuffle(val, 2) * qk_1[2]; @@ -410,40 +428,398 @@ Status FlashAttentionProgram::GenerateShaderCode(ShaderHelper& shader) const { return Status::OK(); } -Status ApplyFlashAttention(const Tensor* Q, const Tensor* K, const Tensor* V, const Tensor* attention_bias, - Tensor* output, const Tensor* past_key, Tensor* present_key, const Tensor* past_value, Tensor* present_value, - const WebgpuAttentionParameters& parameters, onnxruntime::webgpu::ComputeContext& context) { - ORT_RETURN_IF_ERROR(CopyKVCache(context, parameters, K, past_key, present_key, V, past_value, present_value, parameters.past_sequence_length_, parameters.total_sequence_length_)); - - const uint32_t tile_size = 64; - bool has_attention_bias = attention_bias != nullptr; - FlashAttentionProgram program{"FlashAttention", has_attention_bias, parameters.head_size_, parameters.num_heads_}; - program.AddInputs({{Q, ProgramTensorMetadataDependency::TypeAndRank, 4}, - {present_key, ProgramTensorMetadataDependency::TypeAndRank, 4}, - {present_value, ProgramTensorMetadataDependency::TypeAndRank, 4}, - {attention_bias, ProgramTensorMetadataDependency::TypeAndRank}}); - program.AddOutputs({{output, ProgramTensorMetadataDependency::TypeAndRank, 4}}); +Status FlashAttentionDecodeQKTProgram::GenerateShaderCode(ShaderHelper& shader) const { + shader.AddInput("q", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias); + shader.AddInput("present_key", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias); + if (has_attention_bias_) { + shader.AddInput("attention_bias", ShaderUsage::UseUniform); + } + shader.AddOutput("output", ShaderUsage::UseUniform); + shader.AddOutput("metadata", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias); + // Note that this shader adopts similar algorithm with dp4a generation shader. + // + // This algorithm works to compute dot product of keys with queries parallelly, by processing on the k (head_size) dimension at each step amongst tile_size_k_vec threads, + // and utilizing the remaining threads in the workgroup to process additional rows of |present_key| in parallel (such that the values in shared memory (tile_q) for |q| can be reused). + // For each load of q, the tile_size_k_vec threads also reload |present_key| tile_size/sub_tile_count times to compute partial dot products of other |present_key| rows + // in order to complete all tile_size |present_key| rows in this workgroup and also reusing the loaded in register values of |q|. + constexpr int tile_size_k_vec = 8; + + // 1. Each workgroup processes one row of |q| and tile_size rows of |present_key| + // + // 2. Computation Process: + // - Reads [tile_size][tile_size_k_vec] block of |present_key| data at a time + // - Each thread within workgroup computes dot products of 4 A*B elements since each k represents 4 elements of |present_key| + // - Stores intermediate results in shared memory (inner_qk_values) + // - Iterates through columns (head_size_vec) accumulating results in inner_qk_values + // - Performs final reduction sum in inner_qk_values for output + shader.AdditionalImplementation() << "const tile_size = " << tile_size_ << "u;\n" + << "const tile_size_k_vec = " << tile_size_k_vec << "u;\n" + << "const sub_tile_count = " << WorkgroupSizeX() / tile_size_k_vec << "u;\n"; + shader.AdditionalImplementation() << R"ADDNL_FN( +var tile_q: array; +var inner_qk_values: array, tile_size>; +var tile_qk: array; +)ADDNL_FN"; + + if (has_attention_bias_) { + shader.AdditionalImplementation() << R"HELPER_FN( + fn loadAttentionBias(idx: u32) -> q_element_t + { + return attention_bias[idx]; + } + )HELPER_FN"; + } else { + shader.AdditionalImplementation() << R"HELPER_FN( + fn loadAttentionBias(idx: u32) -> q_element_t + { + return q_element_t(0); + } + )HELPER_FN"; + } + + shader.MainFunctionBody() << R"MAIN_FN( + let local_row = u32(local_idx / tile_size_k_vec); + let local_col = local_idx % tile_size_k_vec; + let total_seq_offset = (workgroup_idx % uniforms.num_total_seq_length_tile) * tile_size; + let head_idx = u32(workgroup_idx / uniforms.num_total_seq_length_tile); + let q_offset = head_idx * uniforms.head_size_vec; + var total_sequence_length = uniforms.total_sequence_length; + let present_offset = u32(head_idx / uniforms.n_reps) * uniforms.present_sequence_length * uniforms.head_size_vec; + for (var k: u32 = 0u; k < uniforms.head_size_vec; k += tile_size_k_vec) { + if (local_idx < tile_size_k_vec && k + local_idx < uniforms.head_size_vec) { + tile_q[local_idx] = q[q_offset + k + local_idx]; + } + workgroupBarrier(); + let q_data = tile_q[local_col]; + if (k + local_col < uniforms.head_size_vec) { + for (var row_offset = 0u; row_offset < tile_size; row_offset += sub_tile_count) { + if (total_seq_offset + row_offset + local_row < total_sequence_length) { + inner_qk_values[row_offset + local_row][local_col] += dot(present_key[present_offset + (total_seq_offset + row_offset + local_row) * uniforms.head_size_vec + k + local_col], q_data); + } + } + } + workgroupBarrier(); + } + + if (local_idx < tile_size && total_seq_offset + local_idx < total_sequence_length) { + var sum = q_element_t(0); + for (var i = 0u; i < tile_size_k_vec; i++) { + sum += inner_qk_values[local_idx][i]; + } + + let output_idx = head_idx * total_sequence_length + total_seq_offset + local_idx; + sum = sum * q_element_t(uniforms.alpha) + loadAttentionBias(output_idx); + tile_qk[local_idx] = sum; + output[output_idx] = sum; + } + workgroupBarrier(); + + if (local_idx == 0u) { + // Calculate the max and sum in current split. + var l_max = f32(-3.402823e+38f); + var l_sum = f32(0); + for (var i = 0u; i < tile_size && (total_seq_offset + i) < total_sequence_length; i++) { + l_max = max(l_max, f32(tile_qk[i])); + } + for (var i = 0u; i < tile_size && (total_seq_offset + i) < total_sequence_length; i++) { + l_sum += exp(f32(tile_qk[i]) - l_max); + } + let meta_offset = head_idx * uniforms.num_total_seq_length_tile + workgroup_idx % uniforms.num_total_seq_length_tile; + metadata[meta_offset] = metadata_value_t(metadata_element_t(l_max), metadata_element_t(l_sum)); + } +)MAIN_FN"; + + return Status::OK(); +} + +Status ComputeFlashAttentionDecodeQKT(onnxruntime::webgpu::ComputeContext& context, const Tensor* Q, + const Tensor* attention_bias, Tensor* output, Tensor* present_key, Tensor* metadata, + const WebgpuAttentionParameters& parameters, uint32_t num_total_seq_length_tile, uint32_t tile_size) { const float alpha = parameters.scale_ == 0.0f ? 1.f / sqrt(static_cast(parameters.head_size_)) : parameters.scale_; - std::string cache_hint = std::to_string(has_attention_bias) + - std::to_string(parameters.head_size_) + - std::to_string(parameters.num_heads_); - program.SetDispatchGroupSize(parameters.num_heads_, (parameters.sequence_length_ + tile_size - 1) / tile_size, 1) - .SetWorkgroupSize(tile_size) - .CacheHint(cache_hint) - .AddUniformVariables({{static_cast(parameters.sequence_length_)}, + + const bool has_attention_bias = attention_bias != nullptr; + const int components = 4; + + FlashAttentionDecodeQKTProgram program{"FlashAttentionDecodeQKT", has_attention_bias, tile_size}; + program.AddInputs({{Q, ProgramTensorMetadataDependency::TypeAndRank, components}, + {present_key, ProgramTensorMetadataDependency::TypeAndRank, components}}); + if (has_attention_bias) { + program.AddInput({attention_bias, ProgramTensorMetadataDependency::TypeAndRank}); + } + program.AddOutputs({{output, ProgramTensorMetadataDependency::Rank}, + {metadata, ProgramTensorMetadataDependency::Rank, 2}}); + + const uint32_t vectorized_head_size = parameters.head_size_ / components; + program.SetDispatchGroupSize(parameters.num_heads_ * num_total_seq_length_tile) + .SetWorkgroupSize(64) + .CacheHint(tile_size, has_attention_bias) + .AddUniformVariables({{static_cast(vectorized_head_size)}, {static_cast(parameters.total_sequence_length_)}, - {alpha}}); + {static_cast(alpha)}, + // present_sequence_length is used to index into the KV cache, for static kv cache it is the max sequence length. + {static_cast(parameters.is_gqa_ ? parameters.seqlen_present_kv_cache_ : parameters.total_sequence_length_)}, + {static_cast(parameters.n_reps)}, + {num_total_seq_length_tile}}); return context.RunProgram(program); } +Status FlashAttentionDecodeSplitVxProgram::GenerateShaderCode(ShaderHelper& shader) const { + shader.AddInput("metadata", ShaderUsage::UseUniform); + shader.AddInput("qk", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias); + shader.AddInput("present_value", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias); + shader.AddOutput("out_split_vx", ShaderUsage::UseUniform); + + // Note that this shader adopts similar algorithm with dp4a generation shader. + // + // This algorithm works to compute dot product of v with qk parallelly, by processing on the head_size dimension at each step amongst tile_size_k_vec threads, + // and utilizing the remaining threads in the workgroup to process additional rows of |present_value| in parallel (such that the values in shared memory (tile_qk) for |qk| can be reused). + // The tile_size_k_vec threads also reload |present_value| tile_size/sub_tile_count times to compute partial dot products of other |present_value| rows + // in order to complete all tile_size |present_value| rows in this workgroup and also reusing the values in tile_qk. + // + // The difference with FlashAttentionDecodeQKTProgram is that the dot products go through the rows (total_sequence_length) of |present_value| instead of columns (head_size_vec). + // And each workgroup only calculate current tile_size's dot products instead of iterating the whole row |total_sequence_length|. + // That's why this shader is a split shader. The final reduce will be done in FlashAttentionDecodeReduceProgram. + constexpr int tile_size_k_vec = 8; + + shader.AdditionalImplementation() << "const head_size_vec = " << head_size_vec_ << "u;\n" + << "const tile_size = " << tile_size_ << "u;\n" + << "const tile_size_k_vec = " << tile_size_k_vec << "u;\n" + << "const sub_tile_count = " << WorkgroupSizeX() / tile_size_k_vec << "u;\n"; + shader.AdditionalImplementation() << R"HELPER_FN( +var tile_qk: array; +var tile_output: array; +var qkv_values: array, sub_tile_count>; + + )HELPER_FN"; + + // TODO: Ideally, there should only be two shaders FlashAttentionDecodeSplitVx and FlashAttentionDecodeVxReduce, which can also reduce the intermediate memory. + // The FlashAttentionDecodeQKT can be merged into split shader and do the final softmax adjustment in the reduce shader. However, some issues are met that when + // the total sequence length exceeds some value, the result will become garbage. Since it can't be resolved in a short time, leave it as TODO to fix it in future. + shader.MainFunctionBody() << R"MAIN_FN( + let local_row = u32(local_idx / tile_size_k_vec); + let local_col = local_idx % tile_size_k_vec; + let total_seq_offset = (workgroup_idx % uniforms.num_total_seq_length_tile) * tile_size; + let head_idx = u32(workgroup_idx / uniforms.num_total_seq_length_tile); + var total_sequence_length = uniforms.total_sequence_length; + let present_offset = u32(head_idx / uniforms.n_reps) * uniforms.head_size_vec * uniforms.present_sequence_length; + + // Calculate the global max and sum in qk. + var g_max = f32(-3.402823e+38f); + for (var i = 0u; i < uniforms.num_total_seq_length_tile; i++) + { + let meta_offset = head_idx * uniforms.num_total_seq_length_tile + i; + g_max = max(g_max, f32(metadata[meta_offset].x)); + } + var g_sum = f32(0); + for (var i = 0u; i < uniforms.num_total_seq_length_tile; i++) + { + let meta_offset = head_idx * uniforms.num_total_seq_length_tile + i; + let m_value = metadata[meta_offset]; + g_sum += exp(f32(m_value.x) - g_max) * f32(m_value.y); + } + + if (total_seq_offset + local_idx < total_sequence_length) { + tile_qk[local_idx] = qk_value_t(exp(f32(qk[head_idx * total_sequence_length + total_seq_offset + local_idx]) - g_max) / g_sum); + } + + for (var k: u32 = 0u; k < uniforms.head_size_vec; k += tile_size_k_vec) { + var value = present_value_value_t(0); + qkv_values[local_row][local_col] = present_value_value_t(0); + workgroupBarrier(); + + if (k + local_col < uniforms.head_size_vec) { + for (var row_offset = 0u; row_offset < tile_size; row_offset += sub_tile_count) { + if (total_seq_offset + row_offset + local_row < total_sequence_length) { + value += present_value[present_offset + (total_seq_offset + row_offset + local_row) * uniforms.head_size_vec + k + local_col] * tile_qk[row_offset + local_row]; + } + } + } + + qkv_values[local_row][local_col] = value; + workgroupBarrier(); + + if (local_idx < tile_size_k_vec) { + for (var i = 0u; i < sub_tile_count; i++) { + tile_output[k + local_idx] += qkv_values[i][local_idx]; + } + } + workgroupBarrier(); + } + + for (var i = local_idx; i < uniforms.head_size_vec; i += workgroup_size_x) { + let out_offset = head_idx * uniforms.num_total_seq_length_tile * uniforms.head_size_vec + (workgroup_idx % uniforms.num_total_seq_length_tile) * uniforms.head_size_vec + i; + out_split_vx[out_offset] = tile_output[i]; + } +)MAIN_FN"; + + return Status::OK(); +} + +Status ComputeFlashAttentionDecodeSplitVxScore(onnxruntime::webgpu::ComputeContext& context, + const Tensor* metadata, + const Tensor* qk, + Tensor* out_split_vx, + Tensor* present_value, + const WebgpuAttentionParameters& parameters, + uint32_t num_total_seq_length_tile, + uint32_t tile_size) { + const int components = 4; + int head_size_vec = parameters.v_head_size_ / components; + FlashAttentionDecodeSplitVxProgram program{"FlashAttentionDecodeSplitVx", tile_size, head_size_vec}; + program.AddInputs({{metadata, ProgramTensorMetadataDependency::TypeAndRank, 2}, + {qk, ProgramTensorMetadataDependency::TypeAndRank}, + {present_value, ProgramTensorMetadataDependency::TypeAndRank, components}}); + program.AddOutputs({{out_split_vx, ProgramTensorMetadataDependency::TypeAndRank, components}}); // [B, N, split_k, head_size] + program.SetDispatchGroupSize(parameters.num_heads_ * num_total_seq_length_tile) + .CacheHint(tile_size, head_size_vec) + .SetWorkgroupSize(64) + .AddUniformVariables({{static_cast(parameters.total_sequence_length_)}, + {static_cast(head_size_vec)}, + {static_cast(parameters.is_gqa_ ? parameters.seqlen_present_kv_cache_ : parameters.total_sequence_length_)}, + {static_cast(parameters.n_reps)}, + num_total_seq_length_tile}); + + return context.RunProgram(program); +} + +Status FlashAttentionDecodeVxReduceProgram::GenerateShaderCode(ShaderHelper& shader) const { + shader.AddInput("input", ShaderUsage::UseUniform); + shader.AddOutput("output", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias); + + // Inputs are splits of the GQA output, split into num_total_seq_length_tiles rows. + // This shader needs to add these splits across the row dimension to arrive at the final result. The column is head size wide. + // The reduction achieves maximum parallelization by splitting this task first into tile_size columns that each workgroup is responsible for. + // Then within each workgroup the task of summation over the num_total_seq_length_tile for the tile_size columns is further split in two ways. + // First across the row dimension to have WORKGROUP_SIZE/TILE_SIZE parallel computations of summation of TILE_SIZE rows. + // Then across the column dimension where each thread is responsible for 1 column of the TILE_SIZE columns the workgroup is resposible for. + shader.AdditionalImplementation() << "const TILE_SIZE = " << tile_size_ << ";\n"; + shader.AdditionalImplementation() << R"HELPER_FN( +var tile_input: array, TILE_SIZE>; + )HELPER_FN"; + + shader.MainFunctionBody() << R"MAIN_FN( + let head_size_offset = (workgroup_idx % uniforms.num_head_size_tile) * TILE_SIZE; + let head_idx = u32(workgroup_idx / uniforms.num_head_size_tile); + let in_offset = head_idx * uniforms.num_total_seq_length_tile * uniforms.head_size_vec; + var value = output_value_t(0); + let local_row = u32(local_idx / TILE_SIZE); + let local_col = local_idx % TILE_SIZE; + + if (head_size_offset + local_col < uniforms.head_size_vec) { + for (var r = 0u; r < uniforms.num_total_seq_length_tile; r += TILE_SIZE) { + if (r + local_row < uniforms.num_total_seq_length_tile) { + value += input[in_offset + (r + local_row) * uniforms.head_size_vec + head_size_offset + local_col]; + } + } + } + + tile_input[local_row][local_col] = value; + workgroupBarrier(); + + if (local_idx < TILE_SIZE && head_size_offset + local_idx < uniforms.head_size_vec) { + value = output_value_t(0); + for (var i = 0u; i < TILE_SIZE; i++) { + value += tile_input[i][local_idx]; + } + let output_id = head_idx * uniforms.head_size_vec + head_size_offset + local_idx; + output[output_id] = value; + } +)MAIN_FN"; + + return Status::OK(); +} + +Status ComputeFlashAttentionDecodeVxReduce(onnxruntime::webgpu::ComputeContext& context, + const Tensor* out_split_vx, + Tensor* output, + const WebgpuAttentionParameters& parameters, + uint32_t num_total_seq_length_tile) { + const int components = 4; + constexpr int tile_size = 8; + int tile_head_size = tile_size * components; + FlashAttentionDecodeVxReduceProgram program{"FlashAttentionDecodeVxReduce", tile_size}; + program.AddInputs({{out_split_vx, ProgramTensorMetadataDependency::TypeAndRank, components}}); + program.AddOutputs({{output, ProgramTensorMetadataDependency::TypeAndRank, components}}); + const uint32_t num_head_size_tile = static_cast((parameters.v_head_size_ + tile_head_size - 1) / tile_head_size); + program.SetDispatchGroupSize(parameters.num_heads_ * num_head_size_tile) + .CacheHint(tile_size) + .SetWorkgroupSize(tile_size * tile_size) + .AddUniformVariables({{static_cast(parameters.v_head_size_ / components)}, + num_total_seq_length_tile, + {num_head_size_tile}}); + + return context.RunProgram(program); +} + +Status ApplyFlashAttention(const Tensor* Q, const Tensor* K, const Tensor* V, const Tensor* attention_bias, + Tensor* output, const Tensor* past_key, Tensor* present_key, const Tensor* past_value, Tensor* present_value, + const WebgpuAttentionParameters& parameters, onnxruntime::webgpu::ComputeContext& context) { + ORT_RETURN_IF_ERROR(CopyKVCache(context, parameters, K, past_key, present_key, V, past_value, present_value)); + + if (parameters.sequence_length_ > 1) { + const uint32_t tile_size = 64; + bool has_attention_bias = attention_bias != nullptr; + FlashAttentionProgram program{"FlashAttention", has_attention_bias, parameters.head_size_, parameters.num_heads_}; + program.AddInputs({{Q, ProgramTensorMetadataDependency::TypeAndRank, 4}, + {present_key, ProgramTensorMetadataDependency::TypeAndRank, 4}, + {present_value, ProgramTensorMetadataDependency::TypeAndRank, 4}}); + if (has_attention_bias) { + program.AddInputs({{attention_bias, ProgramTensorMetadataDependency::TypeAndRank}}); + } + program.AddOutputs({{output, ProgramTensorMetadataDependency::TypeAndRank, 4}}); + const float alpha = parameters.scale_ == 0.0f ? 1.f / sqrt(static_cast(parameters.head_size_)) + : parameters.scale_; + std::string cache_hint = std::to_string(has_attention_bias) + + std::to_string(parameters.head_size_) + + std::to_string(parameters.num_heads_); + const uint32_t num_seq_tile = (parameters.sequence_length_ + tile_size - 1) / tile_size; + program.SetDispatchGroupSize(parameters.num_heads_ * num_seq_tile) + .SetWorkgroupSize(tile_size) + .CacheHint(cache_hint) + .AddUniformVariables({{static_cast(parameters.sequence_length_)}, + {static_cast(parameters.total_sequence_length_)}, + {static_cast(parameters.past_present_share_buffer_ ? parameters.past_sequence_length_ : parameters.total_sequence_length_)}, + {static_cast(parameters.total_sequence_length_ - parameters.kv_sequence_length_)}, + {static_cast(parameters.is_gqa_ ? 1 : 0)}, + {static_cast(parameters.n_reps)}, + {alpha}, + {num_seq_tile}}); + + return context.RunProgram(program); + } + + const TensorShapeVector qk_dims({parameters.batch_size_, parameters.num_heads_, + parameters.sequence_length_, parameters.total_sequence_length_}); + const TensorShape qk_shape(qk_dims); + Tensor qk = context.CreateGPUTensor(Q->DataType(), qk_shape); + constexpr uint32_t tile_size = 64; + const uint32_t num_total_seq_length_tile = (parameters.total_sequence_length_ + tile_size - 1) / tile_size; + // The metadata is used to store the max and sum of each tile. + const TensorShapeVector metadata_dims({parameters.batch_size_, parameters.num_heads_, + num_total_seq_length_tile, 2}); + const TensorShape metadata_shape(metadata_dims); + Tensor metadata = context.CreateGPUTensor(Q->DataType(), metadata_shape); + ORT_RETURN_IF_ERROR(ComputeFlashAttentionDecodeQKT(context, Q, attention_bias, &qk, present_key, &metadata, + parameters, num_total_seq_length_tile, tile_size)); + + const TensorShapeVector out_split_vx_dims({parameters.batch_size_, parameters.num_heads_, num_total_seq_length_tile, parameters.head_size_}); + const TensorShape out_split_vx_shape(out_split_vx_dims); + Tensor out_split_vx = context.CreateGPUTensor(Q->DataType(), out_split_vx_shape); + ORT_RETURN_IF_ERROR(ComputeFlashAttentionDecodeSplitVxScore(context, &metadata, &qk, &out_split_vx, present_value, parameters, num_total_seq_length_tile, tile_size)); + ORT_RETURN_IF_ERROR(ComputeFlashAttentionDecodeVxReduce(context, &out_split_vx, output, parameters, num_total_seq_length_tile)); + + return Status::OK(); +} + bool CanApplyFlashAttention(const Tensor* bias, const Tensor* present_key, const Tensor* present_value, const WebgpuAttentionParameters& parameters, onnxruntime::webgpu::ComputeContext& context) { return parameters.batch_size_ == 1 && + !parameters.is_packed_qkv_ && + parameters.head_size_ == parameters.v_head_size_ && bias == nullptr && - parameters.sequence_length_ > 1 && - context.Device().HasFeature(wgpu::FeatureName::Subgroups) && + context.HasFeature(wgpu::FeatureName::Subgroups) && present_key != nullptr && present_value != nullptr && present_key->SizeInBytes() > 0 && present_value->SizeInBytes() > 0 && parameters.head_size_ % 4 == 0; } diff --git a/onnxruntime/contrib_ops/webgpu/bert/flash_attention.h b/onnxruntime/contrib_ops/webgpu/bert/flash_attention.h index 489ae7375ecc3..c066d6249c8b2 100644 --- a/onnxruntime/contrib_ops/webgpu/bert/flash_attention.h +++ b/onnxruntime/contrib_ops/webgpu/bert/flash_attention.h @@ -17,18 +17,19 @@ using namespace onnxruntime::webgpu; class CopyKVCacheProgram final : public Program { public: - CopyKVCacheProgram(const std::string& kernel_name, bool has_past) - : Program{kernel_name}, has_past_(has_past) { + CopyKVCacheProgram(const std::string& kernel_name, bool has_past, bool kv_BNSH, bool past_present_share_buffer) + : Program{kernel_name}, has_past_(has_past), kv_BNSH_(kv_BNSH), past_present_share_buffer_(past_present_share_buffer) { } Status GenerateShaderCode(ShaderHelper& sh) const override; - WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"past_sequence_length", ProgramUniformVariableDataType::Uint32}, - {"kv_sequence_length", ProgramUniformVariableDataType::Uint32}, - {"vectorized_head_size", ProgramUniformVariableDataType::Uint32}); + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"copy_size", ProgramUniformVariableDataType::Uint32}, + {"past_sequence_length", ProgramUniformVariableDataType::Uint32}); private: bool has_past_; + bool kv_BNSH_; + bool past_present_share_buffer_; }; class FlashAttentionProgram final : public Program { @@ -46,8 +47,13 @@ class FlashAttentionProgram final : public Program { Status GenerateShaderCode(ShaderHelper& sh) const override; WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"new_sequence_length", ProgramUniformVariableDataType::Uint32}, + {"total_sequence_length", ProgramUniformVariableDataType::Uint32}, {"present_sequence_length", ProgramUniformVariableDataType::Uint32}, - {"alpha", ProgramUniformVariableDataType::Float32}); + {"past_sequence_length", ProgramUniformVariableDataType::Uint32}, + {"is_gqa", ProgramUniformVariableDataType::Uint32}, + {"n_reps", ProgramUniformVariableDataType::Uint32}, + {"alpha", ProgramUniformVariableDataType::Float32}, + {"num_seq_tile", ProgramUniformVariableDataType::Uint32}); private: bool has_attention_bias_; @@ -55,6 +61,62 @@ class FlashAttentionProgram final : public Program { int qkv_num_heads_; }; +class FlashAttentionDecodeQKTProgram final : public Program { + public: + FlashAttentionDecodeQKTProgram(const std::string& kernel_name, + bool has_attention_bias, uint32_t tile_size) + : Program{kernel_name}, has_attention_bias_(has_attention_bias), tile_size_(tile_size) { + } + + Status GenerateShaderCode(ShaderHelper& sh) const override; + + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"head_size_vec", ProgramUniformVariableDataType::Uint32}, + {"total_sequence_length", ProgramUniformVariableDataType::Uint32}, + {"alpha", ProgramUniformVariableDataType::Float32}, + {"present_sequence_length", ProgramUniformVariableDataType::Uint32}, + {"n_reps", ProgramUniformVariableDataType::Uint32}, + {"num_total_seq_length_tile", ProgramUniformVariableDataType::Uint32}); + + private: + bool has_attention_bias_; + uint32_t tile_size_; +}; + +class FlashAttentionDecodeSplitVxProgram final : public Program { + public: + FlashAttentionDecodeSplitVxProgram(const std::string& kernel_name, uint32_t tile_size, int head_size_vec) + : Program{kernel_name}, tile_size_(tile_size), head_size_vec_(head_size_vec) { + } + + Status GenerateShaderCode(ShaderHelper& sh) const override; + + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"total_sequence_length", ProgramUniformVariableDataType::Uint32}, + {"head_size_vec", ProgramUniformVariableDataType::Uint32}, + {"present_sequence_length", ProgramUniformVariableDataType::Uint32}, + {"n_reps", ProgramUniformVariableDataType::Uint32}, + {"num_total_seq_length_tile", ProgramUniformVariableDataType::Uint32}); + + private: + uint32_t tile_size_; + int head_size_vec_; +}; + +class FlashAttentionDecodeVxReduceProgram final : public Program { + public: + FlashAttentionDecodeVxReduceProgram(const std::string& kernel_name, uint32_t tile_size) + : Program{kernel_name}, tile_size_(tile_size) { + } + + Status GenerateShaderCode(ShaderHelper& sh) const override; + + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"head_size_vec", ProgramUniformVariableDataType::Uint32}, + {"num_total_seq_length_tile", ProgramUniformVariableDataType::Uint32}, + {"num_head_size_tile", ProgramUniformVariableDataType::Uint32}); + + private: + uint32_t tile_size_; +}; + Status ApplyFlashAttention(const Tensor* Q, const Tensor* K, const Tensor* V, const Tensor* attention_bias, Tensor* output, const Tensor* past_key, Tensor* present_key, const Tensor* past_value, Tensor* present_value, const WebgpuAttentionParameters& parameters, onnxruntime::webgpu::ComputeContext& context); diff --git a/onnxruntime/contrib_ops/webgpu/bert/gelu.cc b/onnxruntime/contrib_ops/webgpu/bert/gelu.cc new file mode 100644 index 0000000000000..8dafecfae83e5 --- /dev/null +++ b/onnxruntime/contrib_ops/webgpu/bert/gelu.cc @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/webgpu_supported_types.h" +#include "core/providers/webgpu/math/unary_elementwise_ops.h" // contains Gelu definition +#include "contrib_ops/webgpu/webgpu_contrib_kernels.h" + +namespace onnxruntime { +namespace contrib { +namespace webgpu { + +using namespace onnxruntime::webgpu; +using onnxruntime::webgpu::ComputeContext; + +ONNX_OPERATOR_KERNEL_EX( + Gelu, + kMSDomain, + 1, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T", WebGpuSupportedFloatTypes()), + Gelu); + +} // namespace webgpu +} // namespace contrib +} // namespace onnxruntime \ No newline at end of file diff --git a/onnxruntime/contrib_ops/webgpu/bert/group_query_attention.cc b/onnxruntime/contrib_ops/webgpu/bert/group_query_attention.cc index 31c8af9b4f922..f002db108035f 100644 --- a/onnxruntime/contrib_ops/webgpu/bert/group_query_attention.cc +++ b/onnxruntime/contrib_ops/webgpu/bert/group_query_attention.cc @@ -5,6 +5,8 @@ #include "contrib_ops/webgpu/bert/attention_common.h" #include "contrib_ops/webgpu/bert/group_query_attention.h" #include "contrib_ops/webgpu/webgpu_contrib_kernels.h" +#include "contrib_ops/webgpu/bert/rotary_embedding.h" +#include "contrib_ops/webgpu/bert/flash_attention.h" #include "core/providers/webgpu/webgpu_supported_types.h" @@ -29,6 +31,117 @@ ONNX_OPERATOR_KERNEL_EX( .InputMemoryType(OrtMemTypeCPUInput, 6), GroupQueryAttention); +Status SplitPackedQKVProgram::GenerateShaderCode(ShaderHelper& sh) const { + const auto& packed_qkv = sh.AddInput("packed_qkv", ShaderUsage::UseOffsetToIndices | ShaderUsage::UseUniform); + const auto& query = sh.AddOutput("query", ShaderUsage::UseSetByIndices | ShaderUsage::UseUniform); + const auto& key = sh.AddOutput("key", ShaderUsage::UseSetByIndices | ShaderUsage::UseUniform); + const auto& value = sh.AddOutput("val", ShaderUsage::UseSetByIndices | ShaderUsage::UseUniform); + sh.MainFunctionBody() << " let packed_qkv_indices = " << packed_qkv.OffsetToIndices("global_idx") << ";\n" + << " let input_data = " << packed_qkv.GetByOffset("global_idx") << ";\n" + << " let index = " << packed_qkv.IndicesGet("packed_qkv_indices", "2") << ";\n" + << " if (index < uniforms.hidden_size) {\n" + << " " << query.SetByIndices("packed_qkv_indices", "input_data") << ";\n" + << " } else if (index < (uniforms.hidden_size + uniforms.kv_hidden_size)) {\n" + << " var key_indices = packed_qkv_indices;\n" + << " " << key.IndicesSet("key_indices", "2", "u32(index - uniforms.hidden_size)") << ";\n" + << " " << key.SetByIndices("key_indices", "input_data") << ";\n" + << " } else {\n" + << " var val_indices = packed_qkv_indices;\n" + << " " << value.IndicesSet("val_indices", "2", "u32(index - uniforms.hidden_size - uniforms.kv_hidden_size)") << ";\n" + << " " << value.SetByIndices("val_indices", "input_data") << ";\n" + << " }"; + return Status::OK(); +} + +Status SplitPackedQKV(onnxruntime::webgpu::ComputeContext& context, const WebgpuAttentionParameters& params, const Tensor* packedQKV, Tensor* query, Tensor* key, Tensor* val) { + SplitPackedQKVProgram program; + auto input_size = packedQKV->Shape().Size(); + program + .AddInput({packedQKV, ProgramTensorMetadataDependency::Rank}) + .AddOutputs({{query, ProgramTensorMetadataDependency::Rank}, {key, ProgramTensorMetadataDependency::Rank}, {val, ProgramTensorMetadataDependency::Rank}}) + .AddUniformVariables({ + {static_cast(params.hidden_size_)}, + {static_cast(params.kv_hidden_size_)}, + }) + .SetDispatchGroupSize((input_size + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE); + return context.RunProgram(program); +} + +Status GeneratePositionIDsProgram::GenerateShaderCode(ShaderHelper& sh) const { + const auto& output = sh.AddOutput("output", ShaderUsage::UseUniform); + const auto& seqlens = sh.AddInput("seqlens", ShaderUsage::UseUniform); + sh.MainFunctionBody() << " var pos_id: i32 = 0;\n" + << " let batch_idx = global_idx / uniforms.sequence_length;\n" + << " let sequence_idx = i32(global_idx % uniforms.sequence_length);\n" + << " let seqlen = " << seqlens.GetByOffset("batch_idx") << ";\n"; + if (is_first_prompt_) { + sh.MainFunctionBody() << " let total_seqlen = seqlen + 1;\n" + << " if (sequence_idx < total_seqlen) {\n" + << " pos_id = sequence_idx;\n" + << " } else {\n" + << " pos_id = 1;\n" + << " }\n" + << " " << output.SetByOffset("global_idx", "pos_id") << "\n"; + } else if (is_subsequent_prompt_) { + sh.MainFunctionBody() << " let total_seqlen = seqlen + 1;\n" + << " let past_seqlen = total_seqlen - i32(uniforms.sequence_length);\n" + << " if (past_seqlen + sequence_idx < total_seqlen) {\n" + << " pos_id = past_seqlen + sequence_idx;\n" + << " } else {\n" + << " pos_id = 1;\n" + << " }\n" + << " " << output.SetByOffset("global_idx", "pos_id") << "\n"; + } else { + sh.MainFunctionBody() << " if (global_idx < uniforms.batch_size) {\n" + << " " << output.SetByOffset("global_idx", "seqlen") << "\n" + << " }\n"; + } + return Status::OK(); +} + +Status GeneratePositionIDs(onnxruntime::webgpu::ComputeContext& context, const WebgpuAttentionParameters& params, const Tensor* seqlens, Tensor* output_tensor) { + GeneratePositionIDsProgram program(params.is_first_prompt_, params.is_subsequent_prompt_); + auto output_size = params.batch_size_ * params.sequence_length_; + program.CacheHint(params.is_first_prompt_, params.is_subsequent_prompt_) + .AddInput({seqlens, ProgramTensorMetadataDependency::Rank}) + .AddOutput({output_tensor, ProgramTensorMetadataDependency::Rank}) + .AddUniformVariables({{static_cast(params.batch_size_)}, {static_cast(params.sequence_length_)}}) + .SetDispatchGroupSize((output_size + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE); + return context.RunProgram(program); +} + +Status RunRotaryEmbedding(onnxruntime::webgpu::ComputeContext& context, const WebgpuAttentionParameters& params, const Tensor* input, const Tensor* pos_ids, const Tensor* cos_cache, const Tensor* sin_cache, Tensor* output, bool is_query_input) { + const auto half_rotary_embedding_dim = gsl::narrow_cast(cos_cache->Shape()[1]); + const auto head_size = params.head_size_; + const auto hidden_size = is_query_input ? params.hidden_size_ : params.kv_hidden_size_; + const TensorShape global_shape({params.batch_size_, params.sequence_length_, hidden_size / head_size, static_cast(head_size - half_rotary_embedding_dim)}); + const auto rank = global_shape.NumDimensions(); + std::vector global_dims(rank); + std::vector global_strides(rank); + for (size_t j = 0; j < rank; ++j) { + global_dims[j] = gsl::narrow_cast(global_shape[j]); + global_strides[j] = gsl::narrow_cast(global_shape.SizeFromDimension(j + 1)); + } + const auto input_output_strides = std::vector({gsl::narrow_cast(input->Shape().SizeFromDimension(1)), gsl::narrow_cast(hidden_size), gsl::narrow_cast(head_size), 1}); + const auto output_size = gsl::narrow_cast(global_shape.Size()); + + RotaryEmbeddingProgram program(params.rotary_interleaved_); + program + .CacheHint(params.rotary_interleaved_) + .AddInputs({{input, ProgramTensorMetadataDependency::Rank}, + {pos_ids, ProgramTensorMetadataDependency::Rank}, + {cos_cache, ProgramTensorMetadataDependency::Rank}, + {sin_cache, ProgramTensorMetadataDependency::Rank}}) + .AddOutput(output) + .SetDispatchGroupSize((output_size + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE) + .AddUniformVariables({{params.scale_}, + {gsl::make_span(global_dims)}, + {gsl::make_span(global_strides)}, + {gsl::make_span(input_output_strides)}}) + .AddIndices(TensorShape{1, 1}); + return context.RunProgram(program); +} + Status GroupQueryAttention::ComputeInternal(onnxruntime::webgpu::ComputeContext& context) const { const Tensor* query = context.Input(0); const Tensor* key = context.Input(1); @@ -40,7 +153,7 @@ Status GroupQueryAttention::ComputeInternal(onnxruntime::webgpu::ComputeContext& const Tensor* cos_cache = context.Input(7); const Tensor* sin_cache = context.Input(8); - GroupQueryAttentionParameters params; + GroupQueryAttentionParameters params = {}; ORT_RETURN_IF_ERROR(group_query_attention_helper::CheckInputs(query, key, value, @@ -56,9 +169,6 @@ Status GroupQueryAttention::ComputeInternal(onnxruntime::webgpu::ComputeContext& scale_, softcap_)); WebgpuAttentionParameters parameters(params); - if (parameters.is_packed_qkv_) { - ORT_NOT_IMPLEMENTED("Packed QKV of shape (B, L, N, 3, H) not implemented for webgpu-ep."); - } TensorShapeVector output_shape(3); output_shape[0] = static_cast(parameters.batch_size_); output_shape[1] = static_cast(parameters.sequence_length_); @@ -74,6 +184,39 @@ Status GroupQueryAttention::ComputeInternal(onnxruntime::webgpu::ComputeContext& Tensor* present_value = context.Output(2, present_kv_shape); parameters.past_present_share_buffer_ = present_key != nullptr && present_value != nullptr && past_key != nullptr && past_value != nullptr && past_key->DataRaw() == present_key->DataRaw() && past_value->DataRaw() == present_value->DataRaw(); + if (!do_rotary_ && CanApplyFlashAttention(nullptr /* bias */, present_key, present_value, parameters, context)) { + return ApplyFlashAttention(query, key, value, nullptr /* attention_bias */, output, past_key, present_key, past_value, + present_value, parameters, context); + } + + Tensor qSplit; + Tensor kSplit; + Tensor vSplit; + if (parameters.is_packed_qkv_) { + qSplit = context.CreateGPUTensor(query->DataType(), TensorShape({parameters.batch_size_, parameters.sequence_length_, parameters.hidden_size_})); + kSplit = context.CreateGPUTensor(query->DataType(), TensorShape({parameters.batch_size_, parameters.sequence_length_, parameters.kv_hidden_size_})); + vSplit = context.CreateGPUTensor(query->DataType(), TensorShape({parameters.batch_size_, parameters.sequence_length_, parameters.kv_hidden_size_})); + ORT_RETURN_IF_ERROR(SplitPackedQKV(context, parameters, query, &qSplit, &kSplit, &vSplit)); + parameters.is_packed_qkv_ = false; + query = &qSplit; + key = &kSplit; + value = &vSplit; + } + + Tensor qRotary; + Tensor kRotary; + if (do_rotary_) { + qRotary = context.CreateGPUTensor(query->DataType(), query->Shape()); + kRotary = context.CreateGPUTensor(key->DataType(), key->Shape()); + auto pos_ids_shape = TensorShape({parameters.batch_size_, parameters.sequence_length_}); + Tensor pos_ids = context.CreateGPUTensor(DataTypeImpl::GetType(), pos_ids_shape); + ORT_RETURN_IF_ERROR(GeneratePositionIDs(context, parameters, seqlen_k, &pos_ids)); + ORT_RETURN_IF_ERROR(RunRotaryEmbedding(context, parameters, query, &pos_ids, cos_cache, sin_cache, &qRotary, /* is_query_input = */ true)); + ORT_RETURN_IF_ERROR(RunRotaryEmbedding(context, parameters, key, &pos_ids, cos_cache, sin_cache, &kRotary, /* is_query_input = */ false)); + query = &qRotary; + key = &kRotary; + } + TensorShapeVector q_new_dims({parameters.batch_size_, parameters.num_heads_, parameters.sequence_length_, parameters.head_size_}); TensorShape q_new_shape(q_new_dims); diff --git a/onnxruntime/contrib_ops/webgpu/bert/group_query_attention.h b/onnxruntime/contrib_ops/webgpu/bert/group_query_attention.h index 04969dc778927..1fb1e1ffc91fd 100644 --- a/onnxruntime/contrib_ops/webgpu/bert/group_query_attention.h +++ b/onnxruntime/contrib_ops/webgpu/bert/group_query_attention.h @@ -14,6 +14,29 @@ namespace webgpu { using namespace onnxruntime::webgpu; +class GeneratePositionIDsProgram final : public Program { + public: + GeneratePositionIDsProgram(bool is_first_prompt, bool is_subsequent_prompt) : Program{"GeneratePositionIDs"}, is_first_prompt_(is_first_prompt), is_subsequent_prompt_(is_subsequent_prompt) {} + + Status GenerateShaderCode(ShaderHelper& sh) const override; + + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"batch_size", ProgramUniformVariableDataType::Uint32}, {"sequence_length", ProgramUniformVariableDataType::Uint32}); + + private: + bool is_first_prompt_; + bool is_subsequent_prompt_; +}; + +class SplitPackedQKVProgram final : public Program { + public: + SplitPackedQKVProgram() : Program{"SplitPackedQKV"} {} + + Status GenerateShaderCode(ShaderHelper& sh) const override; + + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"hidden_size", ProgramUniformVariableDataType::Uint32}, + {"kv_hidden_size", ProgramUniformVariableDataType::Uint32}); +}; + class GroupQueryAttention final : public WebGpuKernel { public: GroupQueryAttention(const OpKernelInfo& info) : WebGpuKernel(info) { diff --git a/onnxruntime/contrib_ops/webgpu/bert/multihead_attention.cc b/onnxruntime/contrib_ops/webgpu/bert/multihead_attention.cc index 72931a7310a75..f218b1f0a51ff 100644 --- a/onnxruntime/contrib_ops/webgpu/bert/multihead_attention.cc +++ b/onnxruntime/contrib_ops/webgpu/bert/multihead_attention.cc @@ -42,6 +42,11 @@ Status MultiHeadAttention::ComputeInternal(onnxruntime::webgpu::ComputeContext& const Tensor* past_key = context.Input(6); const Tensor* past_value = context.Input(7); + // Not supported in WebGPU EP currently + const Tensor* cache_indirection = nullptr; + const Tensor* past_sequence_length = nullptr; + constexpr bool past_present_share_buffer = false; + if (query->Shape().GetDims().size() == 5) { ORT_NOT_IMPLEMENTED("Packed QKV of shape (B, L, N, 3, H) not implemented for webgpu"); } @@ -53,9 +58,23 @@ Status MultiHeadAttention::ComputeInternal(onnxruntime::webgpu::ComputeContext& } AttentionParameters params; - ORT_RETURN_IF_ERROR(multihead_attention_helper::CheckInputs(query, key, value, - bias, key_padding_mask, attention_bias, past_key, past_value, nullptr, ¶ms, - num_heads_, mask_filter_value_, scale_, is_unidirectional_, false, kMultiHeadAttention, + ORT_RETURN_IF_ERROR(multihead_attention_helper::CheckInputs(query, + key, + value, + bias, + key_padding_mask, + attention_bias, + past_key, + past_value, + cache_indirection, + past_sequence_length, + ¶ms, + num_heads_, + mask_filter_value_, + scale_, + is_unidirectional_, + past_present_share_buffer, + kMultiHeadAttention, context.DeviceLimits().maxComputeInvocationsPerWorkgroup)); WebgpuAttentionParameters parameters(params); TensorShapeVector output_shape(3); diff --git a/onnxruntime/contrib_ops/webgpu/bert/quick_gelu.cc b/onnxruntime/contrib_ops/webgpu/bert/quick_gelu.cc new file mode 100644 index 0000000000000..7d669e140ef23 --- /dev/null +++ b/onnxruntime/contrib_ops/webgpu/bert/quick_gelu.cc @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/webgpu_supported_types.h" +#include "core/providers/webgpu/math/unary_elementwise_ops.h" // contained Gelu definition +#include "contrib_ops/webgpu/webgpu_contrib_kernels.h" + +namespace onnxruntime { +namespace contrib { +namespace webgpu { + +using namespace onnxruntime::webgpu; +using onnxruntime::webgpu::ComputeContext; + +ONNX_OPERATOR_KERNEL_EX( + QuickGelu, + kMSDomain, + 1, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T", WebGpuSupportedFloatTypes()), + QuickGelu); + +} // namespace webgpu +} // namespace contrib +} // namespace onnxruntime \ No newline at end of file diff --git a/onnxruntime/contrib_ops/webgpu/bert/rotary_embedding.cc b/onnxruntime/contrib_ops/webgpu/bert/rotary_embedding.cc index bc8b7493fc916..8f316cfae80e9 100644 --- a/onnxruntime/contrib_ops/webgpu/bert/rotary_embedding.cc +++ b/onnxruntime/contrib_ops/webgpu/bert/rotary_embedding.cc @@ -27,7 +27,7 @@ Status RotaryEmbeddingProgram::GenerateShaderCode(ShaderHelper& shader) const { const auto& sin_cache = shader.AddInput("sin_cache", ShaderUsage::UseUniform); const auto& output = shader.AddOutput("output", ShaderUsage::UseUniform); // TODO: remove output_indices. - const auto& output_indices = shader.AddIndices("output_indices", false); + const auto& output_indices = shader.AddIndices("output_indices", ShaderUsage::None); const auto interleaved_str = interleaved_ ? "true" : "false"; shader.MainFunctionBody() << " let half_rotary_emb_dim = uniforms.cos_cache_shape[1];\n" " let bsnh = global_idx / uniforms.global_stride % uniforms.global_shape;\n" @@ -66,11 +66,11 @@ Status RotaryEmbedding::ComputeInternal(onnxruntime::webgpu::ComputeContext& con const auto* sin_cache = context.Input(3); auto* output = context.Output(0, input_shape); - const auto batch_size = gsl::narrow(input->Shape()[0]); - const auto batch_stride = gsl::narrow(input_shape.SizeFromDimension(1)); - const auto sequence_length = gsl::narrow(input_shape[input_shape.NumDimensions() - 2]); + const auto batch_size = onnxruntime::narrow(input->Shape()[0]); + const auto batch_stride = onnxruntime::narrow(input_shape.SizeFromDimension(1)); + const auto sequence_length = onnxruntime::narrow(input_shape[input_shape.NumDimensions() - 2]); const auto hidden_size = batch_stride / sequence_length; - const auto half_rotary_embedding_dim = gsl::narrow(cos_cache->Shape()[1]); + const auto half_rotary_embedding_dim = onnxruntime::narrow(cos_cache->Shape()[1]); const auto head_size = rotary_embedding_dim_ == 0 ? half_rotary_embedding_dim * 2 : hidden_size / num_heads_; // Rotary embeddings will be calculated in a pair-wise fashion. In accordance, use the shape @@ -85,11 +85,11 @@ Status RotaryEmbedding::ComputeInternal(onnxruntime::webgpu::ComputeContext& con std::vector global_dims(rank); std::vector global_strides(rank); for (size_t j = 0; j < rank; ++j) { - global_dims[j] = gsl::narrow(global_shape[j]); - global_strides[j] = gsl::narrow(global_shape.SizeFromDimension(j + 1)); + global_dims[j] = onnxruntime::narrow(global_shape[j]); + global_strides[j] = onnxruntime::narrow(global_shape.SizeFromDimension(j + 1)); } - const auto output_size = gsl::narrow(global_shape.Size()); + const auto output_size = onnxruntime::narrow(global_shape.Size()); RotaryEmbeddingProgram program{interleaved_}; const auto input_output_strides = input_shape.NumDimensions() == 3 @@ -100,7 +100,7 @@ Status RotaryEmbedding::ComputeInternal(onnxruntime::webgpu::ComputeContext& con program .CacheHint(interleaved_) - .AddInputs({{input, ProgramTensorMetadataDependency::Rank}, + .AddInputs({{input, ProgramTensorMetadataDependency::TypeAndRank}, {position_ids, ProgramTensorMetadataDependency::Rank}, {cos_cache, ProgramTensorMetadataDependency::Rank}, {sin_cache, ProgramTensorMetadataDependency::Rank}}) diff --git a/onnxruntime/contrib_ops/webgpu/bert/skip_layer_norm.cc b/onnxruntime/contrib_ops/webgpu/bert/skip_layer_norm.cc index a1840257d734f..2126022f8b547 100644 --- a/onnxruntime/contrib_ops/webgpu/bert/skip_layer_norm.cc +++ b/onnxruntime/contrib_ops/webgpu/bert/skip_layer_norm.cc @@ -2,6 +2,8 @@ // Licensed under the MIT License. #include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/string_macros.h" +#include "core/providers/webgpu/webgpu_utils.h" #include "core/providers/webgpu/webgpu_supported_types.h" #include "contrib_ops/webgpu/webgpu_contrib_kernels.h" #include "contrib_ops/webgpu/bert/skip_layer_norm.h" @@ -10,30 +12,8 @@ namespace onnxruntime { namespace contrib { namespace webgpu { -static uint32_t GetMaxComponents(int size) { - if (size % 4 == 0) { - return 4; - } else if (size % 2 == 0) { - return 2; - } - return 1; -} - -static std::string SumVector(std::string x, int components) { - switch (components) { - case 1: - return x; - case 2: - return "(" + x + ".x + " + x + ".y" + ")"; - case 4: - return "(" + x + ".x + " + x + ".y + " + x + ".w + " + x + ".z" + ")"; - default: - ORT_THROW("Unsupported number of components: ", components); - } -} - Status SkipLayerNormProgram::GenerateShaderCode(ShaderHelper& shader) const { - const auto& x = shader.AddInput("x", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias); + const auto& x = shader.AddInput("x", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias); shader.AddInput("skip", ShaderUsage::UseUniform); shader.AddInput("gamma", ShaderUsage::UseUniform); if (hasBeta_) { @@ -47,57 +27,112 @@ Status SkipLayerNormProgram::GenerateShaderCode(ShaderHelper& shader) const { shader.AddOutput("input_skip_bias_sum", ShaderUsage::UseUniform); } - int components = x.NumComponents(); - - std::string bias = (hasBias_) ? " + bias[offset1d + i] " : ""; std::string simpl1 = (simplified_) ? "" : "- mean * mean "; - std::string simpl2 = (simplified_) ? "" : "- element_t(mean) "; - std::string beta = (hasBeta_) ? " + beta[offset1d + i] " : ""; - std::string input_skip_bias_sum = (has_input_skip_bias_sum_) ? "input_skip_bias_sum[offset + i] = value;\n" : ""; - - shader.AdditionalImplementation() - << "alias element_t = " << (is_fp16_ ? "f16;\n" : "f32;\n") - << "alias f32_val_t = " << (components == 4 ? "vec4" : (components == 2 ? "vec2" : "f32")) << ";\n" - << "var sum_shared : array;\n" - << "var sum_squared_shared : array;\n"; - - shader.MainFunctionBody() - << "let ix = local_idx;\n" - << "let iy = global_idx / workgroup_size_x;\n" - << "let hidden_size_vectorized: u32 = uniforms.hidden_size / uniforms.components;\n" - << "var stride = hidden_size_vectorized / workgroup_size_x;\n" - << "let offset = ix * stride + iy * hidden_size_vectorized;\n" - << "let offset1d = stride * ix;\n" - << "if (ix == workgroup_size_x - 1) {\n" - << " stride = hidden_size_vectorized - stride * ix;\n" - << "}\n" - << "for (var i: u32 = 0; i < stride; i++) {\n" - << " let skip_value = skip[offset + i];\n" - << " let input_value = x[offset + i];\n" - << " let value = input_value + skip_value" << bias << ";\n" - << " output[offset + i] = value;\n" - << input_skip_bias_sum - << " let f32_value = f32_val_t(value);\n" - << " sum_shared[ix] += f32_value;\n" - << " sum_squared_shared[ix] += f32_value * f32_value;\n" - << "}\n" - << "workgroupBarrier();\n" - << "var reduce_size : u32 = workgroup_size_x;\n" - << "for (var curr_size = reduce_size >> 1; curr_size > 0; curr_size = reduce_size >> 1) {\n" - << " reduce_size = curr_size + (reduce_size & 1);\n" - << " if (ix < curr_size) {\n" - << " sum_shared[ix] += sum_shared[ix + reduce_size];\n" - << " sum_squared_shared[ix] += sum_squared_shared[ix + reduce_size];\n" - << " }\n" - << " workgroupBarrier();\n" - << "}\n" - << "let sum = sum_shared[0];\n" - << "let square_sum = sum_squared_shared[0];\n" - << "let mean = " << SumVector("sum", components) << " / f32(uniforms.hidden_size);\n" - << "let inv_std_dev = inverseSqrt(" << SumVector("square_sum", components) << " / f32(uniforms.hidden_size) " << simpl1 << "+ uniforms.epsilon);\n" - << "for (var i: u32 = 0; i < stride; i++) {\n" - << " output[offset + i] = (output[offset + i] " << simpl2 << ") * element_t(inv_std_dev) * gamma[offset1d + i]" << beta << ";\n" - << "};\n"; + std::string simpl2 = (simplified_) ? "" : "- x_element_t(mean) "; + if (split_hidden_dim_) { + shader.AdditionalImplementation() + << "var sum_shared : array;\n" + << "var sum_squared_shared : array;\n"; + + SS(input_skip_bias_sum_ss, 512); + if (has_input_skip_bias_sum_) { + input_skip_bias_sum_ss + << " let workgroup_half_idx = uniforms.hidden_size / (workgroup_size_x * 4);\n" + << " if (workgroup_idx >= workgroup_half_idx) {\n" + << " offset = (workgroup_idx - workgroup_half_idx) * workgroup_size_x + local_idx;\n" + << " let skip_value = skip[offset];\n" + << " let input_value = x[offset];\n" + << " let value = input_value + skip_value" << (hasBias_ ? " + bias[offset]" : "") << ";\n" + << " input_skip_bias_sum[offset] = value;\n" + << " return;\n" + << " }\n"; + } + + shader.MainFunctionBody() + << " var offset: u32 = 0;\n" + << (has_input_skip_bias_sum_ ? SS_GET(input_skip_bias_sum_ss) : "") + << " var sum_vec4 = vec4(0);\n" + << " var sum_squared_vec4 = vec4(0);\n" + << " var cur_input_skip_bias_sum = x_value_t(0);\n" + << " for (var i: u32 = 0; i < uniforms.hidden_size / (workgroup_size_x * 4); i++) {\n" + << " let input_offset = i * workgroup_size_x + local_idx;\n" + << " let skip_value = skip[input_offset];\n" + << " let input_value = x[input_offset];\n" + << " let value = input_value + skip_value" << (hasBias_ ? " + bias[input_offset]" : "") << ";\n" + << " if (i == workgroup_idx) {\n" + << " cur_input_skip_bias_sum = value;\n" + << " }\n" + << " let f32_value = vec4(value);\n" + << " sum_vec4 += f32_value;\n" + << " sum_squared_vec4 += f32_value * f32_value;\n" + << " }\n" + << " var sum = " << SumVector("sum_vec4", 4) << ";\n" + << " var sum_squared = " << SumVector("sum_squared_vec4", 4) << ";\n" + << " sum_shared[local_idx] = sum;\n" + << " sum_squared_shared[local_idx] = sum_squared;\n" + << " workgroupBarrier();\n" + << " var reduce_size : u32 = workgroup_size_x;\n" + << " for (var curr_size = reduce_size >> 1; curr_size > 0; curr_size = reduce_size >> 1) {\n" + << " reduce_size = curr_size + (reduce_size & 1);\n" + << " if (local_idx < curr_size) {\n" + << " sum_shared[local_idx] += sum_shared[local_idx + reduce_size];\n" + << " sum_squared_shared[local_idx] += sum_squared_shared[local_idx + reduce_size];\n" + << " }\n" + << " workgroupBarrier();\n" + << " }\n" + << " let mean = sum_shared[0] / f32(uniforms.hidden_size);\n" + << " let inv_std_dev = inverseSqrt(sum_squared_shared[0] / f32(uniforms.hidden_size) " << simpl1 << "+ uniforms.epsilon);\n" + << " offset = workgroup_idx * workgroup_size_x + local_idx;\n" + << " output[offset] = ((cur_input_skip_bias_sum " << simpl2 << ") * x_element_t(inv_std_dev) * gamma[offset]" << (hasBeta_ ? " + beta[offset] " : "") << ");\n"; + } else { + int components = x.NumComponents(); + std::string bias = (hasBias_) ? " + bias[offset1d + i] " : ""; + std::string beta = (hasBeta_) ? " + beta[offset1d + i] " : ""; + std::string input_skip_bias_sum = (has_input_skip_bias_sum_) ? "input_skip_bias_sum[offset + i] = value;\n" : ""; + + shader.AdditionalImplementation() + << "alias f32_val_t = " << (components == 4 ? "vec4" : (components == 2 ? "vec2" : "f32")) << ";\n" + << "var sum_shared : array;\n" + << "var sum_squared_shared : array;\n"; + + shader.MainFunctionBody() + << "let ix = local_idx;\n" + << "let iy = global_idx / workgroup_size_x;\n" + << "let hidden_size_vectorized: u32 = uniforms.hidden_size / uniforms.components;\n" + << "var stride = hidden_size_vectorized / workgroup_size_x;\n" + << "let offset = ix * stride + iy * hidden_size_vectorized;\n" + << "let offset1d = stride * ix;\n" + << "if (ix == workgroup_size_x - 1) {\n" + << " stride = hidden_size_vectorized - stride * ix;\n" + << "}\n" + << "for (var i: u32 = 0; i < stride; i++) {\n" + << " let skip_value = skip[offset + i];\n" + << " let input_value = x[offset + i];\n" + << " let value = input_value + skip_value" << bias << ";\n" + << " output[offset + i] = value;\n" + << input_skip_bias_sum + << " let f32_value = f32_val_t(value);\n" + << " sum_shared[ix] += f32_value;\n" + << " sum_squared_shared[ix] += f32_value * f32_value;\n" + << "}\n" + << "workgroupBarrier();\n" + << "var reduce_size : u32 = workgroup_size_x;\n" + << "for (var curr_size = reduce_size >> 1; curr_size > 0; curr_size = reduce_size >> 1) {\n" + << " reduce_size = curr_size + (reduce_size & 1);\n" + << " if (ix < curr_size) {\n" + << " sum_shared[ix] += sum_shared[ix + reduce_size];\n" + << " sum_squared_shared[ix] += sum_squared_shared[ix + reduce_size];\n" + << " }\n" + << " workgroupBarrier();\n" + << "}\n" + << "let sum = sum_shared[0];\n" + << "let square_sum = sum_squared_shared[0];\n" + << "let mean = " << SumVector("sum", components) << " / f32(uniforms.hidden_size);\n" + << "let inv_std_dev = inverseSqrt(" << SumVector("square_sum", components) << " / f32(uniforms.hidden_size) " << simpl1 << "+ uniforms.epsilon);\n" + << "for (var i: u32 = 0; i < stride; i++) {\n" + << " output[offset + i] = (output[offset + i] " << simpl2 << ") * x_element_t(inv_std_dev) * gamma[offset1d + i]" << beta << ";\n" + << "};\n"; + } return Status::OK(); } @@ -121,19 +156,20 @@ Status SkipLayerNorm::ComputeInternal(onnxruntime::webgpu::ComputeCo return Status::OK(); } - const bool is_fp16 = x->GetElementType() == ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16; - const uint32_t hidden_size = gsl::narrow(x_shape[x_shape.NumDimensions() - 1]); + const uint32_t hidden_size = onnxruntime::narrow(x_shape[x_shape.NumDimensions() - 1]); const int components = GetMaxComponents(hidden_size); const bool has_input_skip_bias_sum = input_skip_bias_sum != nullptr; + const uint32_t norm_count = onnxruntime::narrow(x_shape.SizeToDimension(x_shape.NumDimensions() - 1)); + const bool split_hidden_dim = hidden_size % 512 == 0 && norm_count == 1; - SkipLayerNormProgram program{beta != nullptr, bias != nullptr, epsilon_, hidden_size, has_input_skip_bias_sum, is_fp16, simplified}; + SkipLayerNormProgram program{beta != nullptr, bias != nullptr, epsilon_, hidden_size, has_input_skip_bias_sum, simplified, split_hidden_dim}; program - .CacheHint(simplified, has_input_skip_bias_sum) + .CacheHint(simplified, has_input_skip_bias_sum, split_hidden_dim) .AddInputs({{x, ProgramTensorMetadataDependency::Type, components}}) .AddInputs({{skip, ProgramTensorMetadataDependency::Type, components}}) .AddInputs({{gamma, ProgramTensorMetadataDependency::Type, components}}) .AddOutputs({{output, ProgramTensorMetadataDependency::None, components}}) - .SetDispatchGroupSize(gsl::narrow(ceil(1.0 * data_size / hidden_size))) + .SetDispatchGroupSize(onnxruntime::narrow(ceil(1.0 * data_size / hidden_size))) .AddUniformVariables({ {static_cast(components)}, }) @@ -144,6 +180,13 @@ Status SkipLayerNorm::ComputeInternal(onnxruntime::webgpu::ComputeCo {static_cast(epsilon_)}, }); + if (split_hidden_dim) { + const uint32_t workgroup_size_x = 128; + const uint32_t dispatch_size_x = (has_input_skip_bias_sum ? 2 : 1) * hidden_size / (workgroup_size_x * components); + program.SetDispatchGroupSize(dispatch_size_x, 1, 1) + .SetWorkgroupSize(workgroup_size_x); + } + if (beta != nullptr) { program.AddInput({beta, ProgramTensorMetadataDependency::Type, components}); } diff --git a/onnxruntime/contrib_ops/webgpu/bert/skip_layer_norm.h b/onnxruntime/contrib_ops/webgpu/bert/skip_layer_norm.h index 03de1a4b568b9..73f02f0ad8ec0 100644 --- a/onnxruntime/contrib_ops/webgpu/bert/skip_layer_norm.h +++ b/onnxruntime/contrib_ops/webgpu/bert/skip_layer_norm.h @@ -15,7 +15,7 @@ using onnxruntime::webgpu::ComputeContext; class SkipLayerNormProgram final : public Program { public: - SkipLayerNormProgram(bool hasBeta, bool hasBias, float epsilon, uint32_t hidden_size, bool has_input_skip_bias_sum, bool is_fp16, bool simplified) : Program{"SkipLayerNorm"} { + SkipLayerNormProgram(bool hasBeta, bool hasBias, float epsilon, uint32_t hidden_size, bool has_input_skip_bias_sum, bool simplified, bool split_hidden_dim) : Program{"SkipLayerNorm"} { epsilon_ = epsilon; hasBeta_ = hasBeta; hasBias_ = hasBias; @@ -23,7 +23,7 @@ class SkipLayerNormProgram final : public Program { hidden_size_ = hidden_size; has_input_skip_bias_sum_ = has_input_skip_bias_sum; simplified_ = simplified; - is_fp16_ = is_fp16; + split_hidden_dim_ = split_hidden_dim; } Status GenerateShaderCode(ShaderHelper& sh) const override; @@ -39,8 +39,8 @@ class SkipLayerNormProgram final : public Program { float epsilon_; uint32_t hidden_size_; bool has_input_skip_bias_sum_; - bool is_fp16_; bool simplified_; + bool split_hidden_dim_; }; template diff --git a/onnxruntime/contrib_ops/webgpu/fused_conv.cc b/onnxruntime/contrib_ops/webgpu/fused_conv.cc new file mode 100644 index 0000000000000..e6b7ac3ec24d4 --- /dev/null +++ b/onnxruntime/contrib_ops/webgpu/fused_conv.cc @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/webgpu_supported_types.h" +#include "core/providers/webgpu/nn/conv.h" +#include "contrib_ops/webgpu/webgpu_contrib_kernels.h" +#include "core/providers/webgpu/nn/fuse_utils.h" + +namespace onnxruntime { +namespace contrib { +namespace webgpu { +using onnxruntime::webgpu::Conv; +template +class FusedConv final : public Conv { + public: + FusedConv(const OpKernelInfo& info) : Conv(info) { + ORT_ENFORCE(GetFusedActivationAttr(info, Conv::activation_).IsOK()); + } +}; + +ONNX_OPERATOR_KERNEL_EX( + FusedConv, + kMSDomain, + 1, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T", onnxruntime::webgpu::WebGpuSupportedFloatTypes()), + FusedConv); + +} // namespace webgpu +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/webgpu/quantization/dp4a_matmul_nbits.cc b/onnxruntime/contrib_ops/webgpu/quantization/dp4a_matmul_nbits.cc new file mode 100644 index 0000000000000..ad8319aeff1ad --- /dev/null +++ b/onnxruntime/contrib_ops/webgpu/quantization/dp4a_matmul_nbits.cc @@ -0,0 +1,456 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "contrib_ops/webgpu/quantization/dp4a_matmul_nbits.h" +#include "core/providers/webgpu/shader_helper.h" + +namespace onnxruntime { +namespace contrib { +namespace webgpu { +namespace { + +constexpr std::string_view commonFunctions = R"ADDNL_FN( + fn DequantizedFrom4BitsTo8Bits(in: vec2) -> vec4 + { + var out = vec4(0); + var value_lower = vec4(unpack4xU8(in[0] & 0x0F0F0F0Fu)) - vec4(8); + var value_upper = vec4(unpack4xU8((in[0] >> 4) & 0x0F0F0F0Fu)) - vec4(8); + out[0] = pack4xI8(vec4(value_lower[0], value_upper[0], value_lower[1], value_upper[1])); + out[1] = pack4xI8(vec4(value_lower[2], value_upper[2], value_lower[3], value_upper[3])); + value_lower = vec4(unpack4xU8(in[1] & 0x0F0F0F0Fu)) - vec4(8); + value_upper = vec4(unpack4xU8((in[1] >> 4) & 0x0F0F0F0Fu)) - vec4(8); + out[2] = pack4xI8(vec4(value_lower[0], value_upper[0], value_lower[1], value_upper[1])); + out[3] = pack4xI8(vec4(value_lower[2], value_upper[2], value_lower[3], value_upper[3])); + return out; + } + + // Scaled dot product of 8 packed unsigned integers. + fn SDP8AI(a1:vec4, b1:vec4, a2:vec4, b2:vec4, scale:output_element_t) -> output_element_t + { + var local_sum = dot4I8Packed(a1[0], b1[0]); + local_sum += dot4I8Packed(a1[1], b1[1]); + local_sum += dot4I8Packed(a1[2], b1[2]); + local_sum += dot4I8Packed(a1[3], b1[3]); + local_sum += dot4I8Packed(a2[0], b2[0]); + local_sum += dot4I8Packed(a2[1], b2[1]); + local_sum += dot4I8Packed(a2[2], b2[2]); + local_sum += dot4I8Packed(a2[3], b2[3]); + return output_element_t(local_sum) * scale; + } + )ADDNL_FN"; + +} // namespace + +Status DP4AMatMulQuantizeProgram::GenerateShaderCode(ShaderHelper& shader) const { + shader.AddInput("input_a", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias); + shader.AddOutput("output", ShaderUsage::UseUniform); + shader.AddOutput("scales", ShaderUsage::UseUniform); + shader.MainFunctionBody() << R"MAIN_FN( + var local_a : array, 32>; + var max_value:vec4 = vec4(0); + for (var idx:u32=0;idx<32;idx+=1) + { + local_a[idx] = input_a[workgroup_idx*32 + idx]; + max_value = max(max_value, abs(local_a[idx])); + } + var scale = max(max_value.x, max_value.y); + scale = max(scale, max_value.z); + scale = max(scale, max_value.w); + for (var idx:u32=0;idx<32;idx+=1) + { + output[workgroup_idx*32+idx] = pack4x8snorm(vec4(local_a[idx]/scale)); + } + // 127 is the max value of signed int8 [-127,127] used by pack4x8snorm for 1.0f. + scales[workgroup_idx] = scale/127; + )MAIN_FN"; + return Status::OK(); +} + +Status DP4AMatMulNBitsProgram::GenerateShaderCode(ShaderHelper& shader) const { + shader.AddInput("input_a", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseValueTypeAlias); + shader.AddInput("scales_a", ShaderUsage::UseUniform); + shader.AddInput("input_b", ShaderUsage::UseUniform); + shader.AddInput("scales_b", ShaderUsage::UseUniform); + shader.AddOutput("output", ShaderUsage::UseUniform | ShaderUsage::UseElementTypeAlias); + + // This shader implements co-operative matrix multiply. The key idea here is to + // assume there is a primitive for medium size matrix multiply a subgroup can perform, + // using all its lanes and pooling all its registers to keep the values in registry. + // + // The entire workgroup which has N subgroups first loads a tile into shared memory, + // Then each subgroup loads a subtile from shared memory into registers and uses + // the medium size matrix multiply primitive to perform the math. + // The values for tile/subtile size are chosen to conform to the resource limits + // of an alderlake/tiger lake gpu. A tile is 64x64, workgroup is 256 threads - + // therefore there are 16 subgroups and 16 lanes in each subgroup. + // K the hidden dimension is paged in from RAM at k tile size which is 64. + // All this puts the shared memory requirement slightly above 16KB. + // WebGPU limit is 16KB, output is moved to registers instead of SHM to make + // everything fit in shared memory. + // + // Each subgroup performs a 16 x 64 x 16 multiply which is implemented with + // subgroup shuffle as a placeholder for the day the medium matrix mul primitive + // becomes available in WGSL. The registry requirements is ~2KB per subgroup, on + // Alderlake/Tigerlake subgroup has 8KB of registry space pooling the + // 512B of registry from each lane. + // + // The medium size matmul is implemented using dot4I8Packed, so the inputs for + // this shader require A to be int8 quantized with block size 64. B is regular + // matmulnbits input with block size 32. + + shader.AdditionalImplementation() << commonFunctions + << " const block_size = " << block_size_ << ";"; + + shader.AdditionalImplementation() << R"ADDNL_FN( + const tile_size = 64; + const subtile_size = 16; + const tile_size_k = 32; + const vec_factor = 4; + const u32_factor = 4; + const tile_size_k_vec = 2; + + // Shared memory + var tile_A : array, tile_size>, tile_size_k_vec>; // 64 x 32 + var scale_A : array; // 64 x 1 + var tile_B : array, tile_size>, tile_size_k_vec>; // 64 x 32 + var scale_B : array; // 64 x 1 + + fn loadSHMA(a_global_base:u32, kidx_v:u32, row: u32, col: u32) + { + let a_global = a_global_base + row; + if (a_global >= uniforms.M) + { + return; + } + tile_A[col][row] = input_a[a_global*uniforms.K16+kidx_v+col]; + if (col == 0) + { + // kidx_v - covers 16 values of k + scale_A[row] = scales_a[a_global*(uniforms.K/128) + kidx_v/8]; + } + } + + fn loadSHMB(b_global_base:u32, kidx_v:u32, row: u32, col: u32) + { + let b_global = b_global_base + row; + if (b_global >= uniforms.N) + { + return; + } + + let b_value = input_b[b_global*uniforms.K16+kidx_v+col]; + tile_B[col][row] = DequantizedFrom4BitsTo8Bits(b_value); + if (col == 0) + { + // kidx_v - each kidx_v covers 16 values of k + scale_B[row] = scales_b[b_global*(uniforms.K/block_size) + kidx_v/(block_size/16)]; + } + } + )ADDNL_FN"; + + shader.MainFunctionBody() << R"MAIN_FN( + // During the load phase we use all 256 threads to load 64 rows of A/B. + // For each row we load tile_size_k_vec (2) vectorized elements, which are 32 elements of K. + let a_global_base = u32(workgroup_idx / uniforms.num_N_tile) * tile_size; + let b_global_base = (workgroup_idx % uniforms.num_N_tile) * tile_size; + let load_AorB = u32(local_idx/128); + let load_row = u32((local_idx%128)/2); + let load_col = u32(local_idx%2); + + // During the compute phase, we have the 64x64 tile split into + // subtiles of 16x16. We have a grid of 4x4 subtiles. + let subtile_id = u32(local_idx / subtile_size); + let subtile_idx = u32(subtile_id / 4); + let subtile_idy = u32(subtile_id % 4); + let base_A = subtile_idx * 16; + let base_B = subtile_idy * 16; + // For each subtile we have 16 threads assigned. + let a_idx = u32(local_idx % subtile_size); + + var lane_output1: vec4; + var lane_output2: vec4; + var lane_output3: vec4; + var lane_output4: vec4; + // K's vectrorization is 16 items per index. See input_a/input_b. + // tile_size_k_vec - is the k tile size in vectorized space (1/16). That is + // k tile size is 32. In vectorized space that is 32/16 = 2. + for (var kidx_v:u32 = 0; kidx_v < uniforms.K16; kidx_v+=tile_size_k_vec) + { + // Load Phase: Populate shared memory for the workgroup. + if (load_AorB == 0) + { + loadSHMA(a_global_base, kidx_v, load_row, load_col); + } + else + { + loadSHMB(b_global_base, kidx_v, load_row, load_col); + } + workgroupBarrier(); + + // Compute phase: Perform matmul for this subtile 16 x 32 x 16. + // Step 1: Load from shared memory into registers across entire subgroup. + var own_a0: vec4 = tile_A[0][base_A + a_idx]; + var own_a1: vec4 = tile_A[1][base_A + a_idx]; + var own_scale_a: output_element_t = scale_A[base_A + a_idx]; + if (sg_size == 16) + { + var own_b0: vec4 = tile_B[0][base_B + sg_id]; + var own_b1: vec4 = tile_B[1][base_B + sg_id]; + var own_scale_b: output_element_t = scale_B[base_B + sg_id]; + // Step 2: Access registers across the subgroup using subgroupShuffle and perform the matmul. + lane_output1[0] += SDP8AI(own_a0, subgroupShuffle(own_b0, 0), own_a1, subgroupShuffle(own_b1, 0), subgroupShuffle(own_scale_b, 0) * own_scale_a); + lane_output1[1] += SDP8AI(own_a0, subgroupShuffle(own_b0, 1), own_a1, subgroupShuffle(own_b1, 1), subgroupShuffle(own_scale_b, 1) * own_scale_a); + lane_output1[2] += SDP8AI(own_a0, subgroupShuffle(own_b0, 2), own_a1, subgroupShuffle(own_b1, 2), subgroupShuffle(own_scale_b, 2) * own_scale_a); + lane_output1[3] += SDP8AI(own_a0, subgroupShuffle(own_b0, 3), own_a1, subgroupShuffle(own_b1, 3), subgroupShuffle(own_scale_b, 3) * own_scale_a); + + lane_output2[0] += SDP8AI(own_a0, subgroupShuffle(own_b0, 4), own_a1, subgroupShuffle(own_b1, 4), subgroupShuffle(own_scale_b, 4) * own_scale_a); + lane_output2[1] += SDP8AI(own_a0, subgroupShuffle(own_b0, 5), own_a1, subgroupShuffle(own_b1, 5), subgroupShuffle(own_scale_b, 5) * own_scale_a); + lane_output2[2] += SDP8AI(own_a0, subgroupShuffle(own_b0, 6), own_a1, subgroupShuffle(own_b1, 6), subgroupShuffle(own_scale_b, 6) * own_scale_a); + lane_output2[3] += SDP8AI(own_a0, subgroupShuffle(own_b0, 7), own_a1, subgroupShuffle(own_b1, 7), subgroupShuffle(own_scale_b, 7) * own_scale_a); + + lane_output3[0] += SDP8AI(own_a0, subgroupShuffle(own_b0, 8), own_a1, subgroupShuffle(own_b1, 8), subgroupShuffle(own_scale_b, 8) * own_scale_a); + lane_output3[1] += SDP8AI(own_a0, subgroupShuffle(own_b0, 9), own_a1, subgroupShuffle(own_b1, 9), subgroupShuffle(own_scale_b, 9) * own_scale_a); + lane_output3[2] += SDP8AI(own_a0, subgroupShuffle(own_b0, 10), own_a1, subgroupShuffle(own_b1, 10), subgroupShuffle(own_scale_b, 10) * own_scale_a); + lane_output3[3] += SDP8AI(own_a0, subgroupShuffle(own_b0, 11), own_a1, subgroupShuffle(own_b1, 11), subgroupShuffle(own_scale_b, 11) * own_scale_a); + + lane_output4[0] += SDP8AI(own_a0, subgroupShuffle(own_b0, 12), own_a1, subgroupShuffle(own_b1, 12), subgroupShuffle(own_scale_b, 12) * own_scale_a); + lane_output4[1] += SDP8AI(own_a0, subgroupShuffle(own_b0, 13), own_a1, subgroupShuffle(own_b1, 13), subgroupShuffle(own_scale_b, 13) * own_scale_a); + lane_output4[2] += SDP8AI(own_a0, subgroupShuffle(own_b0, 14), own_a1, subgroupShuffle(own_b1, 14), subgroupShuffle(own_scale_b, 14) * own_scale_a); + lane_output4[3] += SDP8AI(own_a0, subgroupShuffle(own_b0, 15), own_a1, subgroupShuffle(own_b1, 15), subgroupShuffle(own_scale_b, 15) * own_scale_a); + } + else + { + // Code for other subgroup sizes, simply doesnt use subgroups at all. + // Relies on reads from single location tile_B[][base_B + col] by all + // being optimized by the hardware. + lane_output1[0] += SDP8AI(own_a0, tile_B[0][base_B + 0], own_a1, tile_B[1][base_B + 0], own_scale_a * scale_B[base_B + 0]); + lane_output1[1] += SDP8AI(own_a0, tile_B[0][base_B + 1], own_a1, tile_B[1][base_B + 1], own_scale_a * scale_B[base_B + 1]); + lane_output1[2] += SDP8AI(own_a0, tile_B[0][base_B + 2], own_a1, tile_B[1][base_B + 2], own_scale_a * scale_B[base_B + 2]); + lane_output1[3] += SDP8AI(own_a0, tile_B[0][base_B + 3], own_a1, tile_B[1][base_B + 3], own_scale_a * scale_B[base_B + 3]); + + lane_output2[0] += SDP8AI(own_a0, tile_B[0][base_B + 4], own_a1, tile_B[1][base_B + 4], own_scale_a * scale_B[base_B + 4]); + lane_output2[1] += SDP8AI(own_a0, tile_B[0][base_B + 5], own_a1, tile_B[1][base_B + 5], own_scale_a * scale_B[base_B + 5]); + lane_output2[2] += SDP8AI(own_a0, tile_B[0][base_B + 6], own_a1, tile_B[1][base_B + 6], own_scale_a * scale_B[base_B + 6]); + lane_output2[3] += SDP8AI(own_a0, tile_B[0][base_B + 7], own_a1, tile_B[1][base_B + 7], own_scale_a * scale_B[base_B + 7]); + + lane_output3[0] += SDP8AI(own_a0, tile_B[0][base_B + 8], own_a1, tile_B[1][base_B + 8], own_scale_a * scale_B[base_B + 8]); + lane_output3[1] += SDP8AI(own_a0, tile_B[0][base_B + 9], own_a1, tile_B[1][base_B + 9], own_scale_a * scale_B[base_B + 9]); + lane_output3[2] += SDP8AI(own_a0, tile_B[0][base_B + 10], own_a1, tile_B[1][base_B + 10], own_scale_a * scale_B[base_B + 10]); + lane_output3[3] += SDP8AI(own_a0, tile_B[0][base_B + 11], own_a1, tile_B[1][base_B + 11], own_scale_a * scale_B[base_B + 11]); + + lane_output4[0] += SDP8AI(own_a0, tile_B[0][base_B + 12], own_a1, tile_B[1][base_B + 12], own_scale_a * scale_B[base_B + 12]); + lane_output4[1] += SDP8AI(own_a0, tile_B[0][base_B + 13], own_a1, tile_B[1][base_B + 13], own_scale_a * scale_B[base_B + 13]); + lane_output4[2] += SDP8AI(own_a0, tile_B[0][base_B + 14], own_a1, tile_B[1][base_B + 14], own_scale_a * scale_B[base_B + 14]); + lane_output4[3] += SDP8AI(own_a0, tile_B[0][base_B + 15], own_a1, tile_B[1][base_B + 15], own_scale_a * scale_B[base_B + 15]); + } + workgroupBarrier(); + } + + let a_global = a_global_base + base_A + a_idx; + let b_global = b_global_base + base_B; + let output_idx = ((a_global) * uniforms.N + b_global)/4; + // This creates a shader requirement that uniforms.N % 16 == 0 + if (a_global < uniforms.M && b_global < uniforms.N) + { + output[output_idx] = lane_output1; + output[output_idx+1] = lane_output2; + output[output_idx+2] = lane_output3; + output[output_idx+3] = lane_output4; + } + )MAIN_FN"; + + return Status::OK(); +} + +// scale_A components = 1, b components = 4, output components = 1 +Status DP4AMatMulNBitsSmallMProgram::GenerateShaderCode(ShaderHelper& shader) const { + shader.AddInput("input_a", ShaderUsage::UseUniform); + shader.AddInput("scales_a", ShaderUsage::UseUniform); + shader.AddInput("input_b", ShaderUsage::UseUniform); + shader.AddInput("scales_b", ShaderUsage::UseUniform); + shader.AddOutput("output", ShaderUsage::UseUniform | ShaderUsage::UseElementTypeAlias); + // This algorithm works to compute dot product of k parallelly, by processing k at each step amongst tile_size_k_vec threads, + // and utilizing the remaining threads in the workgroup to process additional rows of b in parallel (such that the values in shared memory for A can be reused). + // For each load of k, the tile_size_k_vec threads also reload B tile_size/num_concurrent_b_rows times to compute partial dot products of other B rows + // in order to complete all tile_size b rows in this workgroup and also reusing the loaded in register values of a. + + // 1. Each workgroup handles tile_size_k_vec (16) * k_vectorization_in_b (32) columns (total 512) and num_concurrent_b_rows of matrix B at a time, + // iterating over the columns to compute a partial dot product. + // 2. Uses vec4 vectorization where each K represents 32 elements of matrix B + constexpr uint32_t tile_size_k_vec = 16; + + // 1. Workgroup Responsibility: + // - Processes one row of matrix A + // - Handles tile_size rows of matrix B + // + // 2. Computation Process: + // - Reads [tile_size][tile_size_k_vec] block of B data at a time + // - Each thread within workgroup computes dot products of 32 A*B elements since each K represents 32 elements of matrix B + // - Stores intermediate results in shared memory (inter_results) + // - Iterates through columns accumulating results in inter_results + // - Performs final reduction sum in inter_results for output + shader.AdditionalImplementation() << "const tile_size = " << tile_size_ << "u;\n" + << "const tile_size_k_vec = " << tile_size_k_vec << "u;\n" + // sub_tile_size is the number of concurrent b rows processed by the workgroup. + << "const sub_tile_size = " << WorkgroupSizeX() / tile_size_k_vec << "u;\n"; + shader.AdditionalImplementation() << commonFunctions + << R"ADDNL_FN( + // Shared memory + // Need 2 * tile_size_k_vec (32) to store a tile_A since b is quantized as 4 bits and a is quantized as 8 bits. + var tile_A : array, 32>; + // Need 4 scales value since each tile_A includes 512 (4x4x32) scalars and the block_size is 128. + var scale_A : array; + var inter_results: array, tile_size>; + fn loadSHMA(a_global: u32, kidx_v: u32, col: u32) + { + let k_offset = kidx_v + col; + if (k_offset >= uniforms.K16) { + return; + } + + tile_A[col] = input_a[a_global*uniforms.K16+k_offset]; + if (col < 4) + { + // kidx_v - covers 16 values of k in input_a + scale_A[col] = scales_a[a_global*(uniforms.K/128) + kidx_v/8 + col]; + } + } + )ADDNL_FN"; + + shader.MainFunctionBody() << R"MAIN_FN( + let a_global = u32(workgroup_idx / uniforms.num_N_tile); + let b_global_base = (workgroup_idx % uniforms.num_N_tile) * tile_size; + // Handle each workgroup threads as a block of [sub_tile_size][tile_size_k_vec] + let local_col = local_idx % tile_size_k_vec; + let local_row = local_idx / tile_size_k_vec; + for (var kidx_v:u32 = 0; kidx_v < uniforms.K32; kidx_v += tile_size_k_vec) + { + // Load Phase: Populate shared memory for the workgroup. + if (local_idx < 32) + { + loadSHMA(a_global, kidx_v * 2, local_idx); + } + workgroupBarrier(); + var own_a: vec4 = tile_A[local_col * 2]; + var own_a1: vec4 = tile_A[local_col * 2 + 1]; + var own_scale_a = scale_A[local_col / 4]; + var own_b = vec4(0); + var own_b1 = vec4(0); + let k_offset = kidx_v + local_col; + // calculate intermediate results into inter_results. + for (var row_offset = 0u; row_offset < tile_size; row_offset += sub_tile_size) { + let b_global = b_global_base + row_offset + local_row; + if (b_global < uniforms.N && k_offset < uniforms.K32) + { + let b_offset = b_global * uniforms.K32 + k_offset; + let b_value = input_b[b_offset]; + own_b = DequantizedFrom4BitsTo8Bits(b_value.xy); + own_b1 = DequantizedFrom4BitsTo8Bits(b_value.zw); + + // k_offset - covers 32 values of k in input_b + let own_scale_b = scales_b[b_global * uniforms.K / uniforms.block_size + k_offset * 32 / uniforms.block_size]; + inter_results[row_offset + local_row][local_col] += SDP8AI(own_a, own_b, own_a1, own_b1, own_scale_a * own_scale_b); + } + } + workgroupBarrier(); + } + + if (local_idx < tile_size) { + // Do reduce sum to get final output. + var output_value = output_element_t(0); + for (var b = 0u; b < tile_size_k_vec; b++) { + output_value += inter_results[local_idx][b]; + } + let b_global = b_global_base + local_idx; + let output_idx = a_global * uniforms.N + b_global; + if (b_global < uniforms.N) { + output[output_idx] = output_value; + } + } + )MAIN_FN"; + + return Status::OK(); +} + +Status ApplyDP4AMatrixMatMulNBits(const Tensor* a, const Tensor* b, const Tensor* scales, + uint32_t M, + uint32_t N, + uint32_t K, + uint32_t block_size, + uint32_t min_M_for_tile_optimization, + onnxruntime::webgpu::ComputeContext& context, + Tensor* y) { + constexpr uint32_t kVec4Components = 4; + constexpr uint32_t kVec2Components = 2; + constexpr uint32_t kU32Components = 4; + + constexpr uint32_t kBlockSizeA = 128; + DP4AMatMulQuantizeProgram quantize_program; + quantize_program.SetWorkgroupSize(1); + quantize_program.SetDispatchGroupSize(M * K / kBlockSizeA, 1, 1); + TensorShape a_quant_shape{1, M, K / kU32Components}; + Tensor a_quant = context.CreateGPUTensor(DataTypeImpl::GetType(), a_quant_shape); + TensorShapeVector a_scales_dims({1, 1, M, K / kBlockSizeA}); + Tensor a_scale = context.CreateGPUTensor(a->DataType(), a_scales_dims); + quantize_program.AddInputs({{a, ProgramTensorMetadataDependency::TypeAndRank, static_cast(kVec4Components)}}) + .AddOutputs({{&a_quant, ProgramTensorMetadataDependency::Rank, a_quant.Shape(), 1}, + {&a_scale, ProgramTensorMetadataDependency::Rank, a_scale.Shape(), 1}}); + ORT_RETURN_IF_ERROR(context.RunProgram(quantize_program)); + + if (M < min_M_for_tile_optimization) { + constexpr uint32_t kTileSize = 32; + DP4AMatMulNBitsSmallMProgram mul_program{kTileSize}; + uint32_t num_N_tile = (N + kTileSize - 1) / kTileSize; + mul_program.SetWorkgroupSize(128); + mul_program.SetDispatchGroupSize(M * num_N_tile); + mul_program.AddInputs({{&a_quant, ProgramTensorMetadataDependency::TypeAndRank, static_cast(kVec4Components)}, + {&a_scale, ProgramTensorMetadataDependency::TypeAndRank, 1}, + {b, ProgramTensorMetadataDependency::TypeAndRank, static_cast(kVec4Components * kU32Components)}, + {scales, ProgramTensorMetadataDependency::TypeAndRank, 1}}) + .AddUniformVariables({M, N, K, K / 16, K / 32, block_size, num_N_tile}) + .AddOutput({y, ProgramTensorMetadataDependency::TypeAndRank, 1}); + return context.RunProgram(mul_program); + } + + constexpr uint32_t kTileSize = 64; + TensorShape reshaped_y_shape{1, M, N / kVec4Components}; + uint32_t num_M_tile = (M + kTileSize - 1) / kTileSize; + uint32_t num_N_tile = (N + kTileSize - 1) / kTileSize; + DP4AMatMulNBitsProgram mul_program{block_size}; + mul_program.SetWorkgroupSize(256); + mul_program.SetDispatchGroupSize(num_M_tile * num_N_tile); + mul_program.AddInputs({{&a_quant, ProgramTensorMetadataDependency::TypeAndRank, static_cast(kVec4Components)}, + {&a_scale, ProgramTensorMetadataDependency::TypeAndRank, 1}, + {b, ProgramTensorMetadataDependency::TypeAndRank, static_cast(kVec2Components * kU32Components)}, + {scales, ProgramTensorMetadataDependency::TypeAndRank, 1}}) + .AddUniformVariables({{static_cast(M)}, + {static_cast(N)}, + {static_cast(K)}, + {static_cast(K / 8)}, + {static_cast(K / 16)}, + {num_N_tile}}) + .AddOutput({y, ProgramTensorMetadataDependency::TypeAndRank, reshaped_y_shape, static_cast(kVec4Components)}) + .CacheHint("Block" + std::to_string(block_size)); + return context.RunProgram(mul_program); +} + +bool CanApplyDP4AMatrixMatMulNBits(onnxruntime::webgpu::ComputeContext& context, + uint64_t accuracy_level, + uint32_t block_size, + uint32_t batch_count, + uint32_t N, + uint32_t K, + uint32_t components_k, + bool has_zero_points) { + // macOS - Avoid using dp4a on Metal, as it does not appear to have native dp4a support. + // https://github.com/gpuweb/gpuweb/issues/2677#issuecomment-1713292226 + bool use_dp4a = context.HasFeature(wgpu::FeatureName::Subgroups) && + context.AdapterInfo().backendType != wgpu::BackendType::Metal; + return (accuracy_level == 4 && block_size % 32 == 0 && + batch_count == 1 && components_k == 4 && K % 128 == 0 && N % 16 == 0 && + !has_zero_points && use_dp4a); +} + +} // namespace webgpu +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/webgpu/quantization/dp4a_matmul_nbits.h b/onnxruntime/contrib_ops/webgpu/quantization/dp4a_matmul_nbits.h new file mode 100644 index 0000000000000..67e2e7d66e83a --- /dev/null +++ b/onnxruntime/contrib_ops/webgpu/quantization/dp4a_matmul_nbits.h @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/webgpu/program.h" +#include "core/providers/webgpu/webgpu_kernel.h" + +namespace onnxruntime { +namespace contrib { +namespace webgpu { + +using namespace onnxruntime::webgpu; + +class DP4AMatMulQuantizeProgram final : public Program { + public: + DP4AMatMulQuantizeProgram() : Program{"DP4AMatMulQuantize"} {} + Status GenerateShaderCode(ShaderHelper& sh) const override; +}; + +class DP4AMatMulNBitsProgram final : public Program { + public: + DP4AMatMulNBitsProgram(uint32_t block_size) : Program{"DP4AMatMulNBits"}, block_size_(block_size) {} + Status GenerateShaderCode(ShaderHelper& sh) const override; + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES( + {"M", ProgramUniformVariableDataType::Uint32}, + {"N", ProgramUniformVariableDataType::Uint32}, + {"K", ProgramUniformVariableDataType::Uint32}, + {"K8", ProgramUniformVariableDataType::Uint32}, + {"K16", ProgramUniformVariableDataType::Uint32}, + {"num_N_tile", ProgramUniformVariableDataType::Uint32}); + + private: + uint32_t block_size_; +}; + +class DP4AMatMulNBitsSmallMProgram final : public Program { + public: + DP4AMatMulNBitsSmallMProgram(uint32_t tile_size) : Program{"DP4AMatMulNBitsSmallMProgram"}, tile_size_(tile_size) {} + Status GenerateShaderCode(ShaderHelper& sh) const override; + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES( + {"M", ProgramUniformVariableDataType::Uint32}, + {"N", ProgramUniformVariableDataType::Uint32}, + {"K", ProgramUniformVariableDataType::Uint32}, + {"K16", ProgramUniformVariableDataType::Uint32}, + {"K32", ProgramUniformVariableDataType::Uint32}, + {"block_size", ProgramUniformVariableDataType::Uint32}, + {"num_N_tile", ProgramUniformVariableDataType::Uint32}); + + private: + uint32_t tile_size_; +}; + +Status ApplyDP4AMatrixMatMulNBits(const Tensor* a, const Tensor* b, const Tensor* scales, + uint32_t M, + uint32_t N, + uint32_t K, + uint32_t block_size, + uint32_t min_M_for_tile_optimization, + onnxruntime::webgpu::ComputeContext& context, + Tensor* y); + +bool CanApplyDP4AMatrixMatMulNBits(onnxruntime::webgpu::ComputeContext& context, + uint64_t accuracy_level, + uint32_t block_size, + uint32_t batch_count, + uint32_t N, + uint32_t K, + uint32_t components_k, + bool has_zero_points); + +} // namespace webgpu +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/webgpu/quantization/matmul_nbits.cc b/onnxruntime/contrib_ops/webgpu/quantization/matmul_nbits.cc index 28d622b2c9c33..0e75990045b4a 100644 --- a/onnxruntime/contrib_ops/webgpu/quantization/matmul_nbits.cc +++ b/onnxruntime/contrib_ops/webgpu/quantization/matmul_nbits.cc @@ -5,27 +5,18 @@ #include "contrib_ops/webgpu/quantization/matmul_nbits.h" #include "contrib_ops/webgpu/quantization/subgroup_matrix_matmul_nbits.h" +#include "contrib_ops/webgpu/quantization/dp4a_matmul_nbits.h" #include "contrib_ops/webgpu/webgpu_contrib_kernels.h" #include "core/providers/cpu/math/matmul_helper.h" #include "core/providers/webgpu/shader_helper.h" #include "core/providers/webgpu/webgpu_supported_types.h" +#include "core/providers/webgpu/webgpu_utils.h" namespace onnxruntime { namespace contrib { namespace webgpu { namespace { -// Put it to a common place? -uint32_t GetMaxComponents(uint32_t size) { - // we cannot use vec3 type since it has alignment of 16 bytes - if (size % 4 == 0) { - return 4; - } else if (size % 2 == 0) { - return 2; - } - - return 1; -} std::string QuantizedDataType(int components) { switch (components) { @@ -371,7 +362,7 @@ Status MatMulNBitsProgram::GenerateShaderCode(ShaderHelper& shader) const { } } else { const std::string quantized_data_type = QuantizedDataType(a.NumComponents()); - const int output_element_number = y.NumComponents() * gsl::narrow(output_number_); + const int output_element_number = y.NumComponents() * onnxruntime::narrow(output_number_); const uint32_t shared_memory_size = output_number_ * WORKGROUP_SIZE; std::string offset = "workgroup_idx * " + std::to_string(output_number_); @@ -532,249 +523,119 @@ Status MatMulNBitsProgram::GenerateShaderCode(ShaderHelper& shader) const { return Status::OK(); } -Status DP4AMatMulQuantizeProgram::GenerateShaderCode(ShaderHelper& shader) const { - shader.AddInput("input_a", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias); - shader.AddOutput("output", ShaderUsage::UseUniform); - shader.AddOutput("scales", ShaderUsage::UseUniform); - shader.AdditionalImplementation() << R"ADDNL_FN( - fn readInput(offset: u32) -> input_a_value_t - { - if (offset > uniforms.input_size) { - return input_a_value_t(0); - } - return input_a[offset]; - } -)ADDNL_FN"; - shader.MainFunctionBody() << R"MAIN_FN( - var local_a : array, 32>; - var max_value:vec4 = vec4(0); - for (var idx:u32=0;idx<32;idx+=1) - { - local_a[idx] = readInput(workgroup_idx*32 + idx); - max_value = max(max_value, abs(local_a[idx])); - } - var scale = max(max_value.x, max_value.y); - scale = max(scale, max_value.z); - scale = max(scale, max_value.w); - for (var idx:u32=0;idx<32;idx+=1) - { - output[workgroup_idx*32+idx] = pack4x8snorm(vec4(local_a[idx]/scale)); - } - // 127 is the max value of signed int8 [-127,127] used by pack4x8snorm for 1.0f. - scales[workgroup_idx] = scale/127; -)MAIN_FN"; - return Status::OK(); -} - -Status DP4AMatMulNBitsProgram::GenerateShaderCode(ShaderHelper& shader) const { - shader.AddInput("input_a", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseValueTypeAlias); - shader.AddInput("scales_a", ShaderUsage::UseUniform); - shader.AddInput("input_b", ShaderUsage::UseUniform); - shader.AddInput("scales_b", ShaderUsage::UseUniform); - shader.AddOutput("output", ShaderUsage::UseUniform | ShaderUsage::UseElementTypeAlias); - - // This shader implements co-operative matrix multiply. The key idea here is to - // assume there is a primitive for medium size matrix multiply a subgroup can perform, - // using all its lanes and pooling all its registers to keep the values in registry. - // - // The entire workgroup which has N subgroups first loads a tile into shared memory, - // Then each subgroup loads a subtile from shared memory into registers and uses - // the medium size matrix multiply primitive to perform the math. - // The values for tile/subtile size are chosen to conform to the resource limits - // of an alderlake/tiger lake gpu. A tile is 64x64, workgroup is 256 threads - - // therefore there are 16 subgroups and 16 lanes in each subgroup. - // K the hidden dimension is paged in from RAM at k tile size which is 64. - // All this puts the shared memory requirement slightly above 16KB. - // WebGPU limit is 16KB, output is moved to registers instead of SHM to make - // everything fit in shared memory. - // - // Each subgroup performs a 16 x 64 x 16 multiply which is implemented with - // subgroup shuffle as a placeholder for the day the medium matrix mul primitive - // becomes available in WGSL. The registry requirements is ~2KB per subgroup, on - // Alderlake/Tigerlake subgroup has 8KB of registry space pooling the - // 512B of registry from each lane. - // - // The medium size matmul is implemented using dot4I8Packed, so the inputs for - // this shader require A to be int8 quantized with block size 64. B is regular - // matmulnbits input with block size 32. - - shader.AdditionalImplementation() << R"ADDNL_FN( - const tile_size = 64; - const subtile_size = 16; - const tile_size_k = 32; - const vec_factor = 4; - const u32_factor = 4; - const tile_size_k_vec = 2; - const block_size = 32; - - // Shared memory - var tile_A : array, tile_size>, tile_size_k_vec>; // 64 x 32 - var scale_A : array; // 64 x 1 - var tile_B : array, tile_size>, tile_size_k_vec>; // 64 x 32 - var scale_B : array; // 64 x 1 - - fn loadSHMA(a_global_base:u32, kidx_v:u32, row: u32, col: u32) - { - let a_global = a_global_base + row; - if (a_global >= uniforms.M) - { - return; - } - tile_A[col][row] = input_a[a_global*uniforms.K16+kidx_v+col]; - if (col == 0) - { - // kidx_v - covers 16 values of k - scale_A[row] = scales_a[a_global*(uniforms.K/128) + kidx_v/8]; - } - } - - fn loadSHMB(b_global_base:u32, kidx_v:u32, row: u32, col: u32) - { - let b_global = b_global_base + row; - if (b_global >= uniforms.N) - { - return; - } - - let b_value = input_b[b_global*uniforms.K16+kidx_v+col]; - var b_value_lower = vec4(unpack4xU8(b_value[0] & 0x0F0F0F0Fu)) - vec4(8); - var b_value_upper = vec4(unpack4xU8((b_value[0] >> 4) & 0x0F0F0F0Fu)) - vec4(8); - tile_B[col][row][0] = pack4xI8(vec4(b_value_lower[0], b_value_upper[0], b_value_lower[1], b_value_upper[1])); - tile_B[col][row][1] = pack4xI8(vec4(b_value_lower[2], b_value_upper[2], b_value_lower[3], b_value_upper[3])); - b_value_lower = vec4(unpack4xU8(b_value[1] & 0x0F0F0F0Fu)) - vec4(8); - b_value_upper = vec4(unpack4xU8((b_value[1] >> 4) & 0x0F0F0F0Fu)) - vec4(8); - tile_B[col][row][2] = pack4xI8(vec4(b_value_lower[0], b_value_upper[0], b_value_lower[1], b_value_upper[1])); - tile_B[col][row][3] = pack4xI8(vec4(b_value_lower[2], b_value_upper[2], b_value_lower[3], b_value_upper[3])); - if (col == 0) - { - // kidx_v - each kidx_v covers 16 values of k - scale_B[row] = scales_b[b_global*(uniforms.K/32) + kidx_v/2]; - } - } - - // Scaled dot product of 8 packed unsigned integers. - fn SDP8AI(a1:vec4, b1:vec4, a2:vec4, b2:vec4, scale:output_element_t) -> output_element_t - { - var local_sum = dot4I8Packed(a1[0], b1[0]); - local_sum += dot4I8Packed(a1[1], b1[1]); - local_sum += dot4I8Packed(a1[2], b1[2]); - local_sum += dot4I8Packed(a1[3], b1[3]); - local_sum += dot4I8Packed(a2[0], b2[0]); - local_sum += dot4I8Packed(a2[1], b2[1]); - local_sum += dot4I8Packed(a2[2], b2[2]); - local_sum += dot4I8Packed(a2[3], b2[3]); - return output_element_t(local_sum) * scale; - } -)ADDNL_FN"; +Status MatMulNBitsWideTileProgram::GenerateShaderCode(ShaderHelper& shader) const { + const auto& a = shader.AddInput("input_a", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseValueTypeAlias); + const auto& b = shader.AddInput("input_b", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseValueTypeAlias); + const auto& scales = shader.AddInput("scales", ShaderUsage::UseUniform); + const auto& y = shader.AddOutput("output", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias | ShaderUsage::UseIndicesTypeAlias); + // Bock size 32, `a` component size 4, 8 `a` components per block. + constexpr uint32_t kAComponentsForBlock32 = 8; + + const uint32_t workgroup_size = WorkgroupSizeX() * WorkgroupSizeY(); + ORT_ENFORCE(tile_m_ == workgroup_size / 8, "tile_m must be workgroup_size / 8."); + ORT_ENFORCE(tile_n_ == workgroup_size, "tile_n must be workgroup_size."); + + // memory read/write helpers + shader.AdditionalImplementation() << "fn mm_read_a(batch : u32, row : u32, col : u32) -> input_a_value_t {\n"; + shader.AdditionalImplementation() << " if (row < uniforms.input_a_shape[1] && col < uniforms.input_a_shape[2]) {\n"; + shader.AdditionalImplementation() << " return " << a.GetByIndices("input_a_indices_t(batch, row, col)") << ";\n"; + shader.AdditionalImplementation() << " }\n"; + shader.AdditionalImplementation() << " return input_a_value_t(0);\n"; + shader.AdditionalImplementation() << "}\n"; + + shader.AdditionalImplementation() << "\n"; + shader.AdditionalImplementation() << "fn mm_read_b(row : u32, col : u32) -> input_b_value_t {\n"; + shader.AdditionalImplementation() << " if (row < uniforms.input_b_shape[0] && col < uniforms.input_b_shape[1]) {\n"; + shader.AdditionalImplementation() << " return " << b.GetByIndices("input_b_indices_t(row, col, 0)") << ";\n"; + shader.AdditionalImplementation() << " }\n"; + shader.AdditionalImplementation() << " return input_b_value_t(0);\n"; + shader.AdditionalImplementation() << "}\n"; + + shader.AdditionalImplementation() << "\n"; + shader.AdditionalImplementation() << "fn mm_read_scale(row : u32, col : u32) -> output_value_t {\n"; + shader.AdditionalImplementation() << " if (row < uniforms.input_b_shape[0] && col < uniforms.input_b_shape[1]) {\n"; + shader.AdditionalImplementation() << " return " << scales.GetByOffset("row * uniforms.input_b_shape[1] + col") << ";\n"; + shader.AdditionalImplementation() << " }\n"; + shader.AdditionalImplementation() << " return output_value_t(0);\n"; + shader.AdditionalImplementation() << "}\n"; + + shader.AdditionalImplementation() << "\n"; + shader.AdditionalImplementation() << "fn mm_write_y(batch : u32, row : u32, col : u32, value : output_value_t) {\n"; + shader.AdditionalImplementation() << " if (row < uniforms.output_shape[1] && col < uniforms.output_shape[2]) {\n"; + shader.AdditionalImplementation() << " " << y.SetByIndices("output_indices_t(batch, row, col)", "value") << "\n"; + shader.AdditionalImplementation() << " }\n"; + shader.AdditionalImplementation() << "}\n"; + + // declare const variables + shader.AdditionalImplementation() << "\n"; + shader.AdditionalImplementation() << "// A block32 containing 8 components of `a`." << "\n"; + shader.AdditionalImplementation() << "const kAComponentsForBlock32 = " << kAComponentsForBlock32 << "u;\n"; + shader.AdditionalImplementation() << "const tile_m = " << tile_m_ << "u;\n"; + shader.AdditionalImplementation() << "const tile_n = " << tile_n_ << "u;\n"; + + // declare workgroup memory + shader.AdditionalImplementation() << "\n"; + shader.AdditionalImplementation() << "var a_data_tile: array, tile_m>;\n"; + shader.AdditionalImplementation() << "\n"; + + // main shader.MainFunctionBody() << R"MAIN_FN( - // During the load phase we use all 256 threads to load 64 rows of A/B. - // For each row we load tile_size_k_vec (2) vectorized elements, which are 32 elements of K. - let a_global_base = workgroup_id.x * tile_size; - let b_global_base = workgroup_id.y * tile_size; - let load_AorB = u32(local_idx/128); - let load_row = u32((local_idx%128)/2); - let load_col = u32(local_idx%2); - - // During the compute phase, we have the 64x64 tile split into - // subtiles of 16x16. We have a grid of 4x4 subtiles. - let subtile_id = u32(local_idx / subtile_size); - let subtile_idx = u32(subtile_id / 4); - let subtile_idy = u32(subtile_id % 4); - let base_A = subtile_idx * 16; - let base_B = subtile_idy * 16; - // For each subtile we have 16 threads assigned. - let a_idx = u32(local_idx % subtile_size); - - var lane_output1: vec4; - var lane_output2: vec4; - var lane_output3: vec4; - var lane_output4: vec4; - // K's vectrorization is 16 items per index. See input_a/input_b. - // tile_size_k_vec - is the k tile size in vectorized space (1/16). That is - // k tile size is 32. In vectorized space that is 32/16 = 2. - for (var kidx_v:u32 = 0; kidx_v < uniforms.K16; kidx_v+=tile_size_k_vec) - { - // Load Phase: Populate shared memory for the workgroup. - if (load_AorB == 0) - { - loadSHMA(a_global_base, kidx_v, load_row, load_col); - } - else - { - loadSHMB(b_global_base, kidx_v, load_row, load_col); - } + let batch = workgroup_id.z; + let row = workgroup_id.y * tile_m; + let col = workgroup_id.x * tile_n; + + let a_elements_per_col = uniforms.input_a_shape[2]; + let a_blocks_per_col = (a_elements_per_col + kAComponentsForBlock32 - 1) / kAComponentsForBlock32; + + // Utilizing an f32 accumulator mitigated precision loss with minimal + // performance impact compared to an f16 accumulator. + var results : array; + for (var a_block_idx = 0u; a_block_idx < a_blocks_per_col; a_block_idx++) { + // Load `a` elements into workgroup memory, TileM x kAComponentsForBlock32 (block32) + let a_row_idx = local_idx / kAComponentsForBlock32; + let a_col_idx = local_idx % kAComponentsForBlock32; + a_data_tile[a_row_idx][a_col_idx] = mm_read_a(batch, row + a_row_idx, a_block_idx * kAComponentsForBlock32 + a_col_idx); workgroupBarrier(); - // Compute phase: Perform matmul for this subtile 16 x 32 x 16. - // Step 1: Load from shared memory into registers across entire subgroup. - var own_a0: vec4 = tile_A[0][base_A + a_idx]; - var own_a1: vec4 = tile_A[1][base_A + a_idx]; - var own_scale_a: output_element_t = scale_A[base_A + a_idx]; - if (sg_size == 16) - { - var own_b0: vec4 = tile_B[0][base_B + sg_id]; - var own_b1: vec4 = tile_B[1][base_B + sg_id]; - var own_scale_b: output_element_t = scale_B[base_B + sg_id]; - // Step 2: Access registers across the subgroup using subgroupShuffle and perform the matmul. - lane_output1[0] += SDP8AI(own_a0, subgroupShuffle(own_b0, 0), own_a1, subgroupShuffle(own_b1, 0), subgroupShuffle(own_scale_b, 0) * own_scale_a); - lane_output1[1] += SDP8AI(own_a0, subgroupShuffle(own_b0, 1), own_a1, subgroupShuffle(own_b1, 1), subgroupShuffle(own_scale_b, 1) * own_scale_a); - lane_output1[2] += SDP8AI(own_a0, subgroupShuffle(own_b0, 2), own_a1, subgroupShuffle(own_b1, 2), subgroupShuffle(own_scale_b, 2) * own_scale_a); - lane_output1[3] += SDP8AI(own_a0, subgroupShuffle(own_b0, 3), own_a1, subgroupShuffle(own_b1, 3), subgroupShuffle(own_scale_b, 3) * own_scale_a); - - lane_output2[0] += SDP8AI(own_a0, subgroupShuffle(own_b0, 4), own_a1, subgroupShuffle(own_b1, 4), subgroupShuffle(own_scale_b, 4) * own_scale_a); - lane_output2[1] += SDP8AI(own_a0, subgroupShuffle(own_b0, 5), own_a1, subgroupShuffle(own_b1, 5), subgroupShuffle(own_scale_b, 5) * own_scale_a); - lane_output2[2] += SDP8AI(own_a0, subgroupShuffle(own_b0, 6), own_a1, subgroupShuffle(own_b1, 6), subgroupShuffle(own_scale_b, 6) * own_scale_a); - lane_output2[3] += SDP8AI(own_a0, subgroupShuffle(own_b0, 7), own_a1, subgroupShuffle(own_b1, 7), subgroupShuffle(own_scale_b, 7) * own_scale_a); - - lane_output3[0] += SDP8AI(own_a0, subgroupShuffle(own_b0, 8), own_a1, subgroupShuffle(own_b1, 8), subgroupShuffle(own_scale_b, 8) * own_scale_a); - lane_output3[1] += SDP8AI(own_a0, subgroupShuffle(own_b0, 9), own_a1, subgroupShuffle(own_b1, 9), subgroupShuffle(own_scale_b, 9) * own_scale_a); - lane_output3[2] += SDP8AI(own_a0, subgroupShuffle(own_b0, 10), own_a1, subgroupShuffle(own_b1, 10), subgroupShuffle(own_scale_b, 10) * own_scale_a); - lane_output3[3] += SDP8AI(own_a0, subgroupShuffle(own_b0, 11), own_a1, subgroupShuffle(own_b1, 11), subgroupShuffle(own_scale_b, 11) * own_scale_a); - - lane_output4[0] += SDP8AI(own_a0, subgroupShuffle(own_b0, 12), own_a1, subgroupShuffle(own_b1, 12), subgroupShuffle(own_scale_b, 12) * own_scale_a); - lane_output4[1] += SDP8AI(own_a0, subgroupShuffle(own_b0, 13), own_a1, subgroupShuffle(own_b1, 13), subgroupShuffle(own_scale_b, 13) * own_scale_a); - lane_output4[2] += SDP8AI(own_a0, subgroupShuffle(own_b0, 14), own_a1, subgroupShuffle(own_b1, 14), subgroupShuffle(own_scale_b, 14) * own_scale_a); - lane_output4[3] += SDP8AI(own_a0, subgroupShuffle(own_b0, 15), own_a1, subgroupShuffle(own_b1, 15), subgroupShuffle(own_scale_b, 15) * own_scale_a); - } - else - { - // Code for other subgroup sizes, simply doesnt use subgroups at all. - // Relies on reads from single location tile_B[][base_B + col] by all - // being optimized by the hardware. - lane_output1[0] += SDP8AI(own_a0, tile_B[0][base_B + 0], own_a1, tile_B[1][base_B + 0], own_scale_a * scale_B[base_B + 0]); - lane_output1[1] += SDP8AI(own_a0, tile_B[0][base_B + 1], own_a1, tile_B[1][base_B + 1], own_scale_a * scale_B[base_B + 1]); - lane_output1[2] += SDP8AI(own_a0, tile_B[0][base_B + 2], own_a1, tile_B[1][base_B + 2], own_scale_a * scale_B[base_B + 2]); - lane_output1[3] += SDP8AI(own_a0, tile_B[0][base_B + 3], own_a1, tile_B[1][base_B + 3], own_scale_a * scale_B[base_B + 3]); - - lane_output2[0] += SDP8AI(own_a0, tile_B[0][base_B + 4], own_a1, tile_B[1][base_B + 4], own_scale_a * scale_B[base_B + 4]); - lane_output2[1] += SDP8AI(own_a0, tile_B[0][base_B + 5], own_a1, tile_B[1][base_B + 5], own_scale_a * scale_B[base_B + 5]); - lane_output2[2] += SDP8AI(own_a0, tile_B[0][base_B + 6], own_a1, tile_B[1][base_B + 6], own_scale_a * scale_B[base_B + 6]); - lane_output2[3] += SDP8AI(own_a0, tile_B[0][base_B + 7], own_a1, tile_B[1][base_B + 7], own_scale_a * scale_B[base_B + 7]); - - lane_output3[0] += SDP8AI(own_a0, tile_B[0][base_B + 8], own_a1, tile_B[1][base_B + 8], own_scale_a * scale_B[base_B + 8]); - lane_output3[1] += SDP8AI(own_a0, tile_B[0][base_B + 9], own_a1, tile_B[1][base_B + 9], own_scale_a * scale_B[base_B + 9]); - lane_output3[2] += SDP8AI(own_a0, tile_B[0][base_B + 10], own_a1, tile_B[1][base_B + 10], own_scale_a * scale_B[base_B + 10]); - lane_output3[3] += SDP8AI(own_a0, tile_B[0][base_B + 11], own_a1, tile_B[1][base_B + 11], own_scale_a * scale_B[base_B + 11]); - - lane_output4[0] += SDP8AI(own_a0, tile_B[0][base_B + 12], own_a1, tile_B[1][base_B + 12], own_scale_a * scale_B[base_B + 12]); - lane_output4[1] += SDP8AI(own_a0, tile_B[0][base_B + 13], own_a1, tile_B[1][base_B + 13], own_scale_a * scale_B[base_B + 13]); - lane_output4[2] += SDP8AI(own_a0, tile_B[0][base_B + 14], own_a1, tile_B[1][base_B + 14], own_scale_a * scale_B[base_B + 14]); - lane_output4[3] += SDP8AI(own_a0, tile_B[0][base_B + 15], own_a1, tile_B[1][base_B + 15], own_scale_a * scale_B[base_B + 15]); + let b_row = col + local_idx; + let b_col = a_block_idx; + + let b_data = mm_read_b(b_row, b_col); + let scale = mm_read_scale(b_row, b_col); + let zero_point = output_element_t(8.0); + + // `b` component size is 4. + for (var b_idx = 0u; b_idx < 4u; b_idx++) { + let b_value = b_data[b_idx]; + let b_value_lower = unpack4xU8(b_value & 0x0F0F0F0Fu); + let b_value_upper = unpack4xU8((b_value >> 4u) & 0x0F0F0F0Fu); + let b_quantized_values = mat2x4( + output_element_t(b_value_lower[0]), output_element_t(b_value_upper[0]), + output_element_t(b_value_lower[1]), output_element_t(b_value_upper[1]), + output_element_t(b_value_lower[2]), output_element_t(b_value_upper[2]), + output_element_t(b_value_lower[3]), output_element_t(b_value_upper[3])); + let b_dequantized_values = + (b_quantized_values - mat2x4(zero_point, zero_point, + zero_point, zero_point, + zero_point, zero_point, + zero_point, zero_point)) * scale; + + for (var m_idx = 0u; m_idx < tile_m; m_idx++) { + let a_data0 = a_data_tile[m_idx][b_idx * 2u]; + let a_data1 = a_data_tile[m_idx][b_idx * 2u + 1u]; + + results[m_idx] += f32(dot(a_data0, b_dequantized_values[0u])) + + f32(dot(a_data1, b_dequantized_values[1u])); + } } + workgroupBarrier(); } - let a_global = a_global_base + base_A + a_idx; - let b_global = b_global_base + base_B; - let output_idx = ((a_global) * uniforms.N + b_global)/4; - // This creates a shader requirement that uniforms.N % 16 == 0 - if (a_global < uniforms.M && b_global < uniforms.N) - { - output[output_idx] = lane_output1; - output[output_idx+1] = lane_output2; - output[output_idx+2] = lane_output3; - output[output_idx+3] = lane_output4; + // write the results + for (var m_idx = 0u; m_idx < tile_m; m_idx++) { + mm_write_y(batch, row + m_idx, col + local_idx, output_value_t(results[m_idx])); } )MAIN_FN"; @@ -796,16 +657,16 @@ Status MatMulNBits::ComputeInternal(onnxruntime::webgpu::ComputeContext& context TensorShape b_shape({N_, K_}); ORT_RETURN_IF_ERROR(helper.Compute(a->Shape(), b_shape, false, true)); auto* y = context.Output(0, helper.OutputShape()); - const uint32_t data_size = gsl::narrow(y->Shape().Size()); + const uint32_t data_size = onnxruntime::narrow(y->Shape().Size()); if (data_size == 0) { return Status::OK(); } - const uint32_t batch_count = gsl::narrow(helper.OutputOffsets().size()); - const uint32_t M = gsl::narrow(helper.M()); - const uint32_t N = gsl::narrow(helper.N()); - const uint32_t K = gsl::narrow(helper.K()); - const uint32_t block_size = gsl::narrow(block_size_); + const uint32_t batch_count = onnxruntime::narrow(helper.OutputOffsets().size()); + const uint32_t M = onnxruntime::narrow(helper.M()); + const uint32_t N = onnxruntime::narrow(helper.N()); + const uint32_t K = onnxruntime::narrow(helper.K()); + const uint32_t block_size = onnxruntime::narrow(block_size_); constexpr uint32_t nbits = 4; const uint32_t n_blocks_per_col = (K + block_size - 1) / block_size; @@ -822,56 +683,52 @@ Status MatMulNBits::ComputeInternal(onnxruntime::webgpu::ComputeContext& context return ApplySubgroupMatrixMatMulNBits(a, b, scales, M, N, K, context, y); } - const bool has_subgroup = context.Device().HasFeature(wgpu::FeatureName::Subgroups); - // macOS - Avoid using dp4a on Metal, as it does not appear to have native dp4a support. - // https://github.com/gpuweb/gpuweb/issues/2677#issuecomment-1713292226 - const bool use_dp4a = has_subgroup && context.AdapterInfo().backendType != wgpu::BackendType::Metal; - if (accuracy_level_ == 4 && block_size == 32 && - batch_count == 1 && components_a == 4 && K % 64 == 0 && N % 16 == 0 && - !has_zero_points && use_dp4a && M >= kMinMForTileOptimization) { - constexpr uint32_t kVec4Components = 4; - constexpr uint32_t kVec2Components = 2; - constexpr uint32_t kU32Components = 4; - - constexpr uint32_t kBlockSizeA = 128; - DP4AMatMulQuantizeProgram quantize_program; - quantize_program.SetWorkgroupSize(1); - quantize_program.SetDispatchGroupSize(M * K / kBlockSizeA, 1, 1); - TensorShape a_quant_shape{1, M, K / kU32Components}; - Tensor a_quant = context.CreateGPUTensor(DataTypeImpl::GetType(), a_quant_shape); - TensorShapeVector a_scales_dims({1, 1, M, K / kBlockSizeA}); - Tensor a_scale = context.CreateGPUTensor(a->DataType(), a_scales_dims); - quantize_program.AddInputs({{a, ProgramTensorMetadataDependency::TypeAndRank, gsl::narrow(kVec4Components)}}) - .AddOutputs({{&a_quant, ProgramTensorMetadataDependency::Rank, a_quant.Shape(), gsl::narrow(1)}, - {&a_scale, ProgramTensorMetadataDependency::Rank, a_scale.Shape(), gsl::narrow(1)}}) - .AddUniformVariable({static_cast(M * K / kVec4Components)}); - ORT_RETURN_IF_ERROR(context.RunProgram(quantize_program)); - - constexpr uint32_t kTileSize = 64; - TensorShape reshaped_y_shape{1, M, N / kVec4Components}; - DP4AMatMulNBitsProgram mul_program; - mul_program.SetWorkgroupSize(256); - mul_program.SetDispatchGroupSize( - (M + kTileSize - 1) / kTileSize, - (N + kTileSize - 1) / kTileSize, 1); - mul_program.AddInputs({{&a_quant, ProgramTensorMetadataDependency::TypeAndRank, gsl::narrow(kVec4Components)}, - {&a_scale, ProgramTensorMetadataDependency::TypeAndRank, gsl::narrow(1)}, - {b, ProgramTensorMetadataDependency::TypeAndRank, gsl::narrow(kVec2Components * kU32Components)}, - {scales, ProgramTensorMetadataDependency::TypeAndRank, gsl::narrow(1)}}) - .AddUniformVariables({{static_cast(M)}, - {static_cast(N)}, - {static_cast(K)}, - {static_cast(K / 8)}, - {static_cast(K / 16)}}) - .AddOutput({y, ProgramTensorMetadataDependency::TypeAndRank, reshaped_y_shape, gsl::narrow(kVec4Components)}); - return context.RunProgram(mul_program); + // On FP32 only GPUs, integer math is faster than FP32 therefore always use DP4A independent of length of M. + if ((M >= kMinMForTileOptimization || y->DataType() == DataTypeImpl::GetType()) && CanApplyDP4AMatrixMatMulNBits(context, accuracy_level_, block_size, batch_count, N, K, components_a, has_zero_points)) { + return ApplyDP4AMatrixMatMulNBits(a, b, scales, M, N, K, block_size, kMinMForTileOptimization, context, y); } + // WideTileProgram + // This program is optimized for Block32 prefill using Tile16x128. + // TODO: loosen restrictions on batch_count, has_zero_points, and vendor. + const bool use_wide_tile_program = block_size == 32 && batch_count == 1 && !has_zero_points && + components_a == 4 && components_b == 4 && M >= kMinMForTileOptimization && + context.AdapterInfo().vendor == std::string_view{"intel"}; + if (use_wide_tile_program) { + // Enforce output components to 1. + components = 1; + + constexpr uint32_t workgroup_size = 128; + constexpr uint32_t tile_m = workgroup_size / 8; + constexpr uint32_t tile_n = workgroup_size; + + MatMulNBitsWideTileProgram program{tile_m, tile_n}; + program.SetWorkgroupSize(workgroup_size); + program.SetDispatchGroupSize((N + tile_n - 1) / tile_n, + (M + tile_m - 1) / tile_m, + batch_count); + program.CacheHint("Tile" + std::to_string(tile_m) + "x" + std::to_string(tile_n) + "_Block32"); + + TensorShape reshaped_a_shape{batch_count, M, K / components_a}; + TensorShape reshaped_b_shape{N, n_blocks_per_col, blob_size_in_words / components_b}; + TensorShape reshaped_y_shape{batch_count, M, N / components}; + + program + .AddInputs({{a, ProgramTensorMetadataDependency::TypeAndRank, reshaped_a_shape, onnxruntime::narrow(components_a)}, + {b, ProgramTensorMetadataDependency::TypeAndRank, reshaped_b_shape, onnxruntime::narrow(components_b * 4)}, + {scales, ProgramTensorMetadataDependency::None}}) + .AddOutput({y, ProgramTensorMetadataDependency::TypeAndRank, reshaped_y_shape, onnxruntime::narrow(components)}) + .AddUniformVariable({block_size}); + return context.RunProgram(program); + } + + // Generic program // TODO: Support output_number > 1. Some cases are failed when output_number > 1. constexpr uint32_t output_number = 1; const uint32_t tile_m = M > kMinMForTileOptimization ? 4 : 1; + const bool has_subgroup = context.HasFeature(wgpu::FeatureName::Subgroups); const bool use_subgroup = has_subgroup && context.AdapterInfo().vendor == std::string_view{"intel"} && components_a == 4 && block_size == 32; - MatMulNBitsProgram program{output_number, block_size, tile_m, gsl::narrow(components_b), has_zero_points, use_subgroup}; + MatMulNBitsProgram program{output_number, block_size, tile_m, static_cast(components_b), has_zero_points, use_subgroup}; if (M > kMinMForTileOptimization && block_size == 32) { components = 1; constexpr uint32_t workgroup_size = 64; @@ -884,7 +741,8 @@ Status MatMulNBits::ComputeInternal(onnxruntime::webgpu::ComputeContext& context program.CacheHint("T_M" + std::to_string(tile_m) + "Subgroup" + std::to_string(use_subgroup)); } else if (block_size == 32) { components = 1; - constexpr uint32_t workgroup_size = 64; + // TODO: Tune the workgroup size when `M=1`. + constexpr uint32_t workgroup_size = 128; const uint32_t workgroup_y = N % 8 == 0 ? 8 : 1; const uint32_t workgroup_x = workgroup_size / workgroup_y; program.SetWorkgroupSize(workgroup_x, workgroup_y, 1); @@ -900,10 +758,10 @@ Status MatMulNBits::ComputeInternal(onnxruntime::webgpu::ComputeContext& context TensorShape reshaped_y_shape{batch_count, M, N / components}; program - .AddInputs({{a, ProgramTensorMetadataDependency::TypeAndRank, reshaped_a_shape, gsl::narrow(components_a)}, - {b, ProgramTensorMetadataDependency::TypeAndRank, reshaped_b_shape, gsl::narrow(components_b * 4 /** b will be accessed as uint32 which includs 4 uint8. So here we need to multiply 4.*/)}, + .AddInputs({{a, ProgramTensorMetadataDependency::TypeAndRank, reshaped_a_shape, static_cast(components_a)}, + {b, ProgramTensorMetadataDependency::TypeAndRank, reshaped_b_shape, static_cast(components_b * 4 /** b will be accessed as uint32 which includs 4 uint8. So here we need to multiply 4.*/)}, {scales, ProgramTensorMetadataDependency::None}}) - .AddOutput({y, ProgramTensorMetadataDependency::TypeAndRank, reshaped_y_shape, gsl::narrow(components)}) + .AddOutput({y, ProgramTensorMetadataDependency::TypeAndRank, reshaped_y_shape, static_cast(components)}) .AddUniformVariable({block_size}); if (has_zero_points) { program.AddInput({zero_points, ProgramTensorMetadataDependency::None, {(zero_points->Shape().Size() + 3) / 4}, 4}); diff --git a/onnxruntime/contrib_ops/webgpu/quantization/matmul_nbits.h b/onnxruntime/contrib_ops/webgpu/quantization/matmul_nbits.h index 3d72629bf6b25..07c47021d516a 100644 --- a/onnxruntime/contrib_ops/webgpu/quantization/matmul_nbits.h +++ b/onnxruntime/contrib_ops/webgpu/quantization/matmul_nbits.h @@ -35,23 +35,17 @@ class MatMulNBitsProgram final : public Program { bool use_subgroup_; }; -class DP4AMatMulQuantizeProgram final : public Program { +class MatMulNBitsWideTileProgram final : public Program { public: - DP4AMatMulQuantizeProgram() : Program{"DP4AMatMulQuantize"} {} - Status GenerateShaderCode(ShaderHelper& sh) const override; - WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"input_size", ProgramUniformVariableDataType::Uint32}); -}; + MatMulNBitsWideTileProgram(uint32_t tile_m, uint32_t tile_n) + : Program{"MatMulNBitsWideTileProgram"}, tile_m_(tile_m), tile_n_(tile_n) {} -class DP4AMatMulNBitsProgram final : public Program { - public: - DP4AMatMulNBitsProgram() : Program{"DP4AMatMulNBits"} {} Status GenerateShaderCode(ShaderHelper& sh) const override; - WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES( - {"M", ProgramUniformVariableDataType::Uint32}, - {"N", ProgramUniformVariableDataType::Uint32}, - {"K", ProgramUniformVariableDataType::Uint32}, - {"K8", ProgramUniformVariableDataType::Uint32}, - {"K16", ProgramUniformVariableDataType::Uint32}); + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"block_size", ProgramUniformVariableDataType::Uint32}); + + private: + uint32_t tile_m_; + uint32_t tile_n_; }; class MatMulNBits final : public WebGpuKernel { diff --git a/onnxruntime/contrib_ops/webgpu/quantization/subgroup_matrix_matmul_nbits.cc b/onnxruntime/contrib_ops/webgpu/quantization/subgroup_matrix_matmul_nbits.cc index 2944a4d61b8ef..b1dce049214eb 100644 --- a/onnxruntime/contrib_ops/webgpu/quantization/subgroup_matrix_matmul_nbits.cc +++ b/onnxruntime/contrib_ops/webgpu/quantization/subgroup_matrix_matmul_nbits.cc @@ -185,13 +185,13 @@ Status ApplySubgroupMatrixMatMulNBits(const Tensor* a, const Tensor* b, const Te mul_program.SetDispatchGroupSize( (N + kTileSizeB - 1) / kTileSizeB, (M + kTileSizeA - 1) / kTileSizeA, 1); - mul_program.AddInputs({{a, ProgramTensorMetadataDependency::TypeAndRank, gsl::narrow(1)}, - {b, ProgramTensorMetadataDependency::TypeAndRank, gsl::narrow(kU32Components)}, - {scales, ProgramTensorMetadataDependency::TypeAndRank, gsl::narrow(1)}}) + mul_program.AddInputs({{a, ProgramTensorMetadataDependency::TypeAndRank, 1}, + {b, ProgramTensorMetadataDependency::TypeAndRank, static_cast(kU32Components)}, + {scales, ProgramTensorMetadataDependency::TypeAndRank, 1}}) .AddUniformVariables({{static_cast(M)}, {static_cast(N)}, {static_cast(K)}}) - .AddOutput({y, ProgramTensorMetadataDependency::TypeAndRank, y_shape, gsl::narrow(1)}); + .AddOutput({y, ProgramTensorMetadataDependency::TypeAndRank, y_shape, 1}); return context.RunProgram(mul_program); } @@ -203,7 +203,7 @@ bool CanApplySubgroupMatrixMatMulNBits(onnxruntime::webgpu::ComputeContext& cont uint32_t K, bool has_zero_points) { #if !defined(__wasm__) - const bool has_subgroup_matrix = context.Device().HasFeature(wgpu::FeatureName::ChromiumExperimentalSubgroupMatrix); + const bool has_subgroup_matrix = context.HasFeature(wgpu::FeatureName::ChromiumExperimentalSubgroupMatrix); #else const bool has_subgroup_matrix = false; #endif diff --git a/onnxruntime/contrib_ops/webgpu/webgpu_contrib_kernels.cc b/onnxruntime/contrib_ops/webgpu/webgpu_contrib_kernels.cc index 2e7ed5a16a2f0..4136477a1d88c 100644 --- a/onnxruntime/contrib_ops/webgpu/webgpu_contrib_kernels.cc +++ b/onnxruntime/contrib_ops/webgpu/webgpu_contrib_kernels.cc @@ -37,15 +37,15 @@ Status RegisterWebGpuContribKernels(KernelRegistry& kernel_registry) { static const BuildKernelCreateInfoFn function_table[] = { BuildKernelCreateInfo, // default entry to avoid the list become empty after ops-reducing // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, - // BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, // LayerNormalization used to be a contrib op that (incorrectly) used kOnnxDomain so we need to version it diff --git a/onnxruntime/core/framework/compute_capability.h b/onnxruntime/core/framework/compute_capability.h index 5f21ba2f013e0..819264b3960e7 100644 --- a/onnxruntime/core/framework/compute_capability.h +++ b/onnxruntime/core/framework/compute_capability.h @@ -2,8 +2,11 @@ // Licensed under the MIT License. #pragma once +#include #include "core/common/common.h" #include "core/graph/indexed_sub_graph.h" +#include "core/graph/graph.h" +#include "core/optimizer/graph_optimizer_registry.h" namespace onnxruntime { // A structure encodes a subgraph and the method to run it. @@ -21,5 +24,22 @@ struct ComputeCapability { ComputeCapability(std::unique_ptr t_sub_graph) : sub_graph(std::move(t_sub_graph)) {} + + // Optional function to optimize this ComputeCapability. + // This will be called by ORT once the ComputeCapability is assigned to the EP. + std::function + optimization_func; + + // Optional ComputeCapability instances for sets of nodes within this ComputeCapability that should be optimized. + // when an optimization is applied, ORT will update this ComputeCapability to reflect the changes made. + // IndexedSubGraph.nodes: + // - update based on RemovedNode/AddNode calls + // IndexedSubGraph.MetaDef (if present): + // - inputs and outputs will be unchanged + // - constant_initializers MAY change if we constant fold an initializer during optimization + std::vector> nodes_to_optimize; }; } // namespace onnxruntime diff --git a/onnxruntime/core/framework/error_code_helper.h b/onnxruntime/core/framework/error_code_helper.h index 703d183ea5c87..b42c6a9ba3e10 100644 --- a/onnxruntime/core/framework/error_code_helper.h +++ b/onnxruntime/core/framework/error_code_helper.h @@ -17,16 +17,19 @@ Status ToStatus(const OrtStatus* ort_status, common::StatusCategory category = c #ifndef ORT_NO_EXCEPTIONS #define API_IMPL_BEGIN try { -#define API_IMPL_END \ - } \ - catch (const onnxruntime::NotImplementedException& ex) { \ - return OrtApis::CreateStatus(ORT_NOT_IMPLEMENTED, ex.what()); \ - } \ - catch (const std::exception& ex) { \ - return OrtApis::CreateStatus(ORT_RUNTIME_EXCEPTION, ex.what()); \ - } \ - catch (...) { \ - return OrtApis::CreateStatus(ORT_FAIL, "Unknown Exception"); \ +#define API_IMPL_END \ + } \ + catch (const onnxruntime::OnnxRuntimeException& ex) { \ + return OrtApis::CreateStatus(static_cast(ex.Code()), ex.what()); \ + } \ + catch (const onnxruntime::NotImplementedException& ex) { \ + return OrtApis::CreateStatus(ORT_NOT_IMPLEMENTED, ex.what()); \ + } \ + catch (const std::exception& ex) { \ + return OrtApis::CreateStatus(ORT_RUNTIME_EXCEPTION, ex.what()); \ + } \ + catch (...) { \ + return OrtApis::CreateStatus(ORT_FAIL, "Unknown Exception"); \ } #else diff --git a/onnxruntime/core/framework/execution_provider.cc b/onnxruntime/core/framework/execution_provider.cc index 3a937a119d03b..df85daa006a43 100644 --- a/onnxruntime/core/framework/execution_provider.cc +++ b/onnxruntime/core/framework/execution_provider.cc @@ -14,6 +14,7 @@ namespace onnxruntime { std::vector> IExecutionProvider::GetCapability(const onnxruntime::GraphViewer& graph, const IKernelLookup& kernel_lookup, + const GraphOptimizerRegistry&, IResourceAccountant*) const { std::vector> result; for (const auto& node : graph.Nodes()) { diff --git a/onnxruntime/core/framework/external_data_loader.cc b/onnxruntime/core/framework/external_data_loader.cc index fe73a55735631..c577805e69cc4 100644 --- a/onnxruntime/core/framework/external_data_loader.cc +++ b/onnxruntime/core/framework/external_data_loader.cc @@ -60,7 +60,12 @@ common::Status LoadWebAssemblyExternalData(const Env& env, break; case 1: // Load external data to GPU. - Module.jsepUploadExternalBuffer(dataIdOrBuffer, data); + // TODO: use a unified interface for upload external buffer. + if (Module.webgpuUploadExternalBuffer) { + Module.webgpuUploadExternalBuffer(dataIdOrBuffer, data); + } else { + Module.jsepUploadExternalBuffer(dataIdOrBuffer, data); + } break; default: return 4; // Unknown error occurred in memory copy. diff --git a/onnxruntime/core/framework/external_data_loader.h b/onnxruntime/core/framework/external_data_loader.h index 117da7d0a4afa..90d48ca800797 100644 --- a/onnxruntime/core/framework/external_data_loader.h +++ b/onnxruntime/core/framework/external_data_loader.h @@ -42,7 +42,7 @@ class IExternalDataLoader { enum class ExternalDataLoadType { CPU = 0, -#if defined(USE_JSEP) +#if defined(USE_JSEP) || defined(USE_WEBGPU) WEBGPU_BUFFER = 1, #endif }; diff --git a/onnxruntime/core/framework/graph_partitioner.cc b/onnxruntime/core/framework/graph_partitioner.cc index 111f8e0a5fc34..50f14104cfd7a 100644 --- a/onnxruntime/core/framework/graph_partitioner.cc +++ b/onnxruntime/core/framework/graph_partitioner.cc @@ -56,6 +56,7 @@ namespace { // contains some common parameters used by the partitioning helper functions struct PartitionParams { std::reference_wrapper graph; + std::reference_wrapper check_load_cancellation_fn; #if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) std::reference_wrapper func_mgr; std::reference_wrapper fused_kernel_registry; @@ -142,13 +143,16 @@ struct GetCapabilityForEPParams { std::reference_wrapper debug_graph_fn; #endif // !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) IResourceAccountant* resource_accountant; + std::reference_wrapper graph_optimizer_registry; + std::reference_wrapper check_load_cancellation_fn; }; auto get_capabilities = [](const IExecutionProvider& ep, const GraphViewer& graph_viewer, const IExecutionProvider::IKernelLookup& kernel_lookup, - IResourceAccountant* resource_accountant) { - auto capabilities = ep.GetCapability(graph_viewer, kernel_lookup, resource_accountant); + IResourceAccountant* resource_accountant, + const GraphOptimizerRegistry& graph_optimizer_registry) { + auto capabilities = ep.GetCapability(graph_viewer, kernel_lookup, graph_optimizer_registry, resource_accountant); // In theory an EP could return an empty capability. Remove those. capabilities.erase(std::remove_if(capabilities.begin(), capabilities.end(), @@ -182,10 +186,16 @@ static Status GetCapabilityForEP(const GetCapabilityForEPParams& params, const l auto& graph = params.graph.get(); auto& capabilities = params.capabilities.get(); + const auto& graph_optimizer_registry = params.graph_optimizer_registry.get(); { const GraphViewer graph_viewer(graph); - capabilities = get_capabilities(current_ep, graph_viewer, kernel_lookup, params.resource_accountant); + capabilities = get_capabilities(current_ep, graph_viewer, kernel_lookup, params.resource_accountant, + graph_optimizer_registry); + if (params.check_load_cancellation_fn()) { + return ORT_MAKE_STATUS(ONNXRUNTIME, MODEL_LOAD_CANCELED, + "Graph partitioning was canceled by user request"); + } if (capabilities.empty()) { return Status::OK(); @@ -206,6 +216,10 @@ static Status GetCapabilityForEP(const GetCapabilityForEPParams& params, const l // Perform layout transformation on the specific EP assigned graph bool modified = false; ORT_RETURN_IF_ERROR(params.transform_layout(graph, modified, current_ep, params.debug_graph_fn)); + if (params.check_load_cancellation_fn()) { + return ORT_MAKE_STATUS(ONNXRUNTIME, MODEL_LOAD_CANCELED, + "GetCapabilities was canceled by user request"); + } // It is possible some new nodes are introduced during transformation. These nodes can be either existing nodes // which are reconstructed to update domain or completely new nodes which are necessary for layout transformation. @@ -223,7 +237,12 @@ static Status GetCapabilityForEP(const GetCapabilityForEPParams& params, const l capabilities.clear(); const GraphViewer graph_viewer(graph); - capabilities = get_capabilities(current_ep, graph_viewer, kernel_lookup, params.resource_accountant); + capabilities = get_capabilities(current_ep, graph_viewer, kernel_lookup, params.resource_accountant, + graph_optimizer_registry); + if (params.check_load_cancellation_fn()) { + return ORT_MAKE_STATUS(ONNXRUNTIME, MODEL_LOAD_CANCELED, + "GetCapabilities was canceled by user request"); + } // all nodes with an index >= first_new_node with domain of kMSInternalNHWCDomain should be in the capabilities InlinedHashSet new_nodes_in_capabilities; @@ -261,6 +280,7 @@ static Status GetCapabilityForEP(const GetCapabilityForEPParams& params, const l static Status GetCapabilityForEPForAotInlining(const GraphViewer& graph_viewer, const KernelRegistryManager& kernel_registry_mgr, const IExecutionProvider& current_ep, + const GraphOptimizerRegistry& graph_optimizer_registry, const logging::Logger& logger, std::vector>& capabilities) { const auto& ep_type = current_ep.Type(); @@ -272,14 +292,62 @@ static Status GetCapabilityForEPForAotInlining(const GraphViewer& graph_viewer, logger}; // TODO: Provide EP with a capability to look inside the functions. - capabilities = get_capabilities(current_ep, graph_viewer, kernel_lookup, nullptr); + capabilities = get_capabilities(current_ep, graph_viewer, kernel_lookup, nullptr, graph_optimizer_registry); return Status::OK(); } /** - * Check if a node can be placed on a specific provider. - * Do nothing if the node is already assigned + * Check whether the given IndexedSubGraph is available for assigning to a specific provider. + * + */ +static bool IsIndexedSubGraphAvailableForAssignment(Graph& graph, + const IndexedSubGraph& capability, + GraphPartitioner::Mode mode, + const std::string& provider_type) { + // The provider can run a single node in the if not using meta-defs. + if (capability.GetMetaDef() == nullptr && capability.nodes.size() == 1) { + auto* node = graph.GetNode(capability.nodes[0]); + if (nullptr != node && node->GetExecutionProviderType().empty()) { + // The node was not fused or assigned. + return true; + } + return false; + } + + // if mode is kAssignOnly we want all nodes that can _potentially_ be taken by compiling EPs to be assigned, + // so that we aggregate the nodes covered and ensure the original nodes remain in the ORT format model by + // preventing level 2 and 3 optimizers from changing them. optimizers check the EP the node is assigned to + // and only make changes if the EP is on the optimizer's list of supported EPs. an EP that compiles nodes + // should never be on those lists. + // + // when the ORT format model is loaded we will process it normally with EP priority being applied for + // whichever EPs are enabled at the time. + // + // e.g. an Android NNAPI EP may take different/overlapping nodes to a iOS CoreML EP. + // We want the ORT format model to be able to be run as efficiently as possible on either platform, + // so we want all the nodes that either may take to be preserved. If we did not do this we would + // need to create one ORT format model for Android and one for iOS. + if (mode == GraphPartitioner::Mode::kAssignOnly) { + return true; + } + + for (auto node_index : capability.nodes) { + const auto* node = graph.GetNode(node_index); + if ((nullptr == node) || + (!node->GetExecutionProviderType().empty() && node->GetExecutionProviderType() != provider_type)) { + // The node was fused or assigned, so that the whole sub-graph will not be assigned to this + // The assumption is that this can only run the sub-graph as a whole unit. + return false; + } + } + + return true; +} + +/** + * Return a fused node or assign the nodes in the indexed subgraph to the current EP. + * * \param graph * \param capability * \param kernel_registry_mgr @@ -298,75 +366,42 @@ static Node* PlaceNode(Graph& graph, const IndexedSubGraph& capability, if (nullptr == capability.GetMetaDef()) { TryAssignSingleNode(graph, capability, provider_type); } else { - // The can run a fused in the . + const bool acc_enabled = capability.IsAccountingEnabled(); + if (mode == GraphPartitioner::Mode::kNormal) { + std::ostringstream oss; + oss << provider_type << "_" << capability.GetMetaDef()->name << "_" << fused_node_unique_id++; + std::string node_name = oss.str(); - // Check whether any node in the was already assigned. If so it cannot be stolen as assignment is done - // in order of EP priority - bool sub_graph_available_for_assignment = true; - if (mode != GraphPartitioner::Mode::kAssignOnly) { - // if mode is kAssignOnly we want all nodes that can _potentially_ be taken by compiling EPs to be assigned, - // so that we aggregate the nodes covered and ensure the original nodes remain in the ORT format model by - // preventing level 2 and 3 optimizers from changing them. optimizers check the EP the node is assigned to - // and only make changes if the EP is on the optimizer's list of supported EPs. an EP that compiles nodes - // should never be on those lists. - // - // when the ORT format model is loaded we will process it normally with EP priority being applied for - // whichever EPs are enabled at the time. - // - // e.g. an Android NNAPI EP may take different/overlapping nodes to a iOS CoreML EP. - // We want the ORT format model to be able to be run as efficiently as possible on either platform, - // so we want all the nodes that either may take to be preserved. If we did not do this we would - // need to create one ORT format model for Android and one for iOS. - for (auto node_index : capability.nodes) { - const auto* node = graph.GetNode(node_index); - if ((nullptr == node) || - (!node->GetExecutionProviderType().empty() && node->GetExecutionProviderType() != provider_type)) { - // The node was fused or assigned, so that the whole sub-graph will not be assigned to this - // The assumption is that this can only run the sub-graph as a whole unit. - sub_graph_available_for_assignment = false; - break; - } + Node* fused_node = nullptr; + if (fusion_style == IExecutionProvider::FusionStyle::Function) { + fused_node = &graph.FuseSubGraph(capability, node_name); + } else { + // create a fused node without copying everything to a Function body. The IndexedSubGraph will be passed + // through to Compile via a filtered GraphViewer. + fused_node = &graph.BeginFuseSubGraph(capability, node_name); } - } - - if (sub_graph_available_for_assignment) { - const bool acc_enabled = capability.IsAccountingEnabled(); - if (mode == GraphPartitioner::Mode::kNormal) { - std::ostringstream oss; - oss << provider_type << "_" << capability.GetMetaDef()->name << "_" << fused_node_unique_id++; - std::string node_name = oss.str(); - - Node* fused_node = nullptr; - if (fusion_style == IExecutionProvider::FusionStyle::Function) { - fused_node = &graph.FuseSubGraph(capability, node_name); - } else { - // create a fused node without copying everything to a Function body. The IndexedSubGraph will be passed - // through to Compile via a filtered GraphViewer. - fused_node = &graph.BeginFuseSubGraph(capability, node_name); - } - fused_node->SetExecutionProviderType(provider_type); - if (acc_enabled) { - // We account for the fused node. We operate under assumption - // that the fused node would use no more memory when the nodes we are fusing. - // and potentially less than that, and therefore, no threshold check is needed here. - // All threshold checks are done within the EP. - capability.ComputeAndAccountForNode(*fused_node); - } + fused_node->SetExecutionProviderType(provider_type); + if (acc_enabled) { + // We account for the fused node. We operate under assumption + // that the fused node would use no more memory when the nodes we are fusing. + // and potentially less than that, and therefore, no threshold check is needed here. + // All threshold checks are done within the EP. + capability.ComputeAndAccountForNode(*fused_node); + } - result = fused_node; - } else { - // assign the nodes in the indexed subgraph to the current EP so that level 2+ optimizers will not change them. - // This is used when exporting an ORT format model to maintain the original nodes and re-do the fusion - // at runtime. The original nodes provide a fallback if fewer nodes can be fused at runtime due to device - // capabilities. - for (size_t i = 0, limit = capability.nodes.size(); i < limit; ++i) { - auto* node = graph.GetNode(capability.nodes[i]); - if (node != nullptr) { - node->SetExecutionProviderType(provider_type); - if (acc_enabled) { - capability.AccountForNode(i); - } + result = fused_node; + } else { + // assign the nodes in the indexed subgraph to the current EP so that level 2+ optimizers will not change them. + // This is used when exporting an ORT format model to maintain the original nodes and re-do the fusion + // at runtime. The original nodes provide a fallback if fewer nodes can be fused at runtime due to device + // capabilities. + for (size_t i = 0, limit = capability.nodes.size(); i < limit; ++i) { + auto* node = graph.GetNode(capability.nodes[i]); + if (node != nullptr) { + node->SetExecutionProviderType(provider_type); + if (acc_enabled) { + capability.AccountForNode(i); } } } @@ -386,7 +421,9 @@ static Status PartitionOnnxFormatModelImpl(Graph& graph, FuncManager& func_mgr, int& fused_node_unique_id, const layout_transformation::TransformLayoutFunction& transform_layout_fn, const layout_transformation::DebugGraphFn& debug_graph_fn, - const logging::Logger& logger, IResourceAccountant* resource_accountant) { + const CheckLoadCancellationFn& check_load_cancellation_fn, + const logging::Logger& logger, IResourceAccountant* resource_accountant, + const GraphOptimizerRegistry& graph_optimizer_registry) { // handle testing edge case where optimizers or constant lifting results in graph with no nodes. // doing it here saves all providers checking for this in GetCapability if (graph.NumberOfNodes() == 0) { @@ -400,7 +437,10 @@ static Status PartitionOnnxFormatModelImpl(Graph& graph, FuncManager& func_mgr, // we pass through the FuncManager from the top level graph ORT_RETURN_IF_ERROR(PartitionOnnxFormatModelImpl(*subgraph, func_mgr, kernel_registry_mgr, fused_kernel_registry, current_ep, mode, fused_node_unique_id, - transform_layout_fn, debug_graph_fn, logger, resource_accountant)); + transform_layout_fn, debug_graph_fn, + check_load_cancellation_fn, + logger, resource_accountant, + graph_optimizer_registry)); } } @@ -424,7 +464,9 @@ static Status PartitionOnnxFormatModelImpl(Graph& graph, FuncManager& func_mgr, mode, std::cref(transform_layout_fn), std::cref(debug_graph_fn), - resource_accountant}; + resource_accountant, + std::ref(graph_optimizer_registry), + std::cref(check_load_cancellation_fn)}; ORT_RETURN_IF_ERROR(GetCapabilityForEP(get_capability_params, logger)); if (capabilities.empty()) { @@ -450,7 +492,30 @@ static Status PartitionOnnxFormatModelImpl(Graph& graph, FuncManager& func_mgr, entry->sub_graph->GetMetaDef() != nullptr; })); for (auto& capability : capabilities) { - Node* n = PlaceNode(graph, *capability->sub_graph, fusion_style, type, mode, fused_node_unique_id); + // The can run a fused in the . + // Check whether any node in the was already assigned. If so it cannot be stolen as assignment is done + // in order of EP priority + bool sub_graph_available_for_assignment = IsIndexedSubGraphAvailableForAssignment(graph, *capability->sub_graph, mode, type); + + // If the is available to be assigned to the EP and the ComputeCapability has nodes_to_optimize, + // run EP related optimizations and update ComputeCapability. + if (sub_graph_available_for_assignment && !capability->nodes_to_optimize.empty()) { + for (auto& optimization_cc : capability->nodes_to_optimize) { + if (optimization_cc->optimization_func) { + auto status = optimization_cc->optimization_func(graph, *optimization_cc, *capability, graph_optimizer_registry); + if (status != Status::OK()) { + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, type, "The optimization function failed to finish."); + } + // #TODO: Handle nested optimization ComputeCapability + } + } + } + + Node* n = nullptr; + if (sub_graph_available_for_assignment) { + n = PlaceNode(graph, *capability->sub_graph, fusion_style, type, mode, fused_node_unique_id); + } + if (n != nullptr) { // searching in kernel registries, if no kernel registered for the fused_node, use compile approach if (!KernelRegistryManager::HasImplementationOf(kernel_registry_mgr, *n, type, logger)) { @@ -488,6 +553,8 @@ static Status PartitionOnnxFormatModelImpl(Graph& graph, FuncManager& func_mgr, } ORT_RETURN_IF_ERROR(current_ep.Compile(nodes_and_viewers, node_compute_funcs)); + ORT_RETURN_IF(check_load_cancellation_fn(), + "Graph partitioning is canceled due to user request."); if (node_compute_funcs.size() != nodes_to_compile.size()) { return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, type, " did not return correct number of compiled functions"); @@ -587,7 +654,9 @@ static Status InlineNodes(Graph& graph, bool& modified_graph) { static Status InlineFunctionsAOTImpl(const ExecutionProviders& execution_providers, const KernelRegistryManager& kernel_registry_mgr, Graph& graph, + const GraphOptimizerRegistry& graph_optimizer_registry, const logging::Logger& logger, + const CheckLoadCancellationFn& check_load_cancellation_fn, InlinedHashSet& not_inlined, size_t& inlined_count) { // handle testing edge case where optimizers or constant lifting results in graph with no nodes. @@ -603,7 +672,9 @@ static Status InlineFunctionsAOTImpl(const ExecutionProviders& execution_provide ORT_RETURN_IF_ERROR(InlineFunctionsAOTImpl(execution_providers, kernel_registry_mgr, *subgraph, + graph_optimizer_registry, logger, + check_load_cancellation_fn, not_inlined, inlined_count)); } @@ -627,8 +698,13 @@ static Status InlineFunctionsAOTImpl(const ExecutionProviders& execution_provide InlinedHashSet claimed_by_ep; for (const auto& ep : execution_providers) { std::vector> capabilities; - ORT_RETURN_IF_ERROR(GetCapabilityForEPForAotInlining(graph_viewer, kernel_registry_mgr, *ep, logger, + ORT_RETURN_IF_ERROR(GetCapabilityForEPForAotInlining(graph_viewer, kernel_registry_mgr, *ep, + graph_optimizer_registry, logger, capabilities)); + if (check_load_cancellation_fn()) { + return ORT_MAKE_STATUS(ONNXRUNTIME, MODEL_LOAD_CANCELED, "AOT inlining is canceled due to user request."); + } + for (auto& capability : capabilities) { const auto& nodes = capability->sub_graph->nodes; if (nodes.size() == 1) { @@ -661,29 +737,37 @@ static Status InlineFunctionsAOTImpl(const ExecutionProviders& execution_provide ORT_IGNORE_RETURN_VALUE(not_inlined.insert(std::move(function_id))); } } + if (check_load_cancellation_fn()) { + return ORT_MAKE_STATUS(ONNXRUNTIME, MODEL_LOAD_CANCELED, "AOT inlining is canceled due to user request."); + } } return Status::OK(); } // Validate the ep_context_path to make sure it is file path and check whether the file exist already -static Status EpContextFilePathCheck(const std::string& ep_context_path, - const std::filesystem::path& model_path) { - std::filesystem::path context_cache_path; +static Status GetValidatedEpContextPath(const std::filesystem::path& ep_context_path, + const std::filesystem::path& model_path, + std::filesystem::path& context_cache_path) { if (!ep_context_path.empty()) { context_cache_path = ep_context_path; if (!context_cache_path.has_filename()) { return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "context_file_path should not point to a folder."); } } else if (!model_path.empty()) { - context_cache_path = model_path.native() + ORT_TSTR("_ctx.onnx"); + auto pos = model_path.native().find_last_of(ORT_TSTR(".")); + if (pos != std::string::npos) { + context_cache_path = model_path.native().substr(0, pos) + ORT_TSTR("_ctx.onnx"); + } else { + context_cache_path = model_path.native() + ORT_TSTR("_ctx.onnx"); + } } else { return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Both ep_context_path and model_path are empty."); } if (std::filesystem::exists(context_cache_path)) { return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Failed to generate EP context model since the file '", - context_cache_path, "' exist already."); + context_cache_path, "' exist already. Please remove the EP context model if you want to re-generate it."); } return Status::OK(); @@ -714,15 +798,7 @@ static Status CreateEpContextModel(const ExecutionProviders& execution_providers }; std::filesystem::path context_cache_path; - const std::filesystem::path& model_path = graph.ModelPath(); - - if (!ep_context_path.empty()) { - context_cache_path = ep_context_path; - } else if (!model_path.empty()) { - context_cache_path = model_path.native() + ORT_TSTR("_ctx.onnx"); - } else { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Both ep_context_path and model_path are empty"); - } + ORT_RETURN_IF_ERROR(GetValidatedEpContextPath(ep_context_path, graph.ModelPath(), context_cache_path)); Model ep_context_model(graph.Name(), false, graph.GetModel().MetaData(), graph.GetModel().ModelPath(), // use source model path so that external initializers can find the data file path @@ -794,6 +870,7 @@ static Status PartitionOnnxFormatModel(const PartitionParams& partition_params, const ExecutionProviders& execution_providers, KernelRegistryManager& kernel_registry_manager, const std::optional& acc_map, + const GraphOptimizerRegistry& graph_optimizer_registry, const logging::Logger& logger) { bool modified_graph = false; @@ -802,6 +879,7 @@ static Status PartitionOnnxFormatModel(const PartitionParams& partition_params, auto& fused_kernel_registry = partition_params.fused_kernel_registry.get(); auto& fused_node_unique_id = partition_params.fused_node_unique_id.get(); const auto& transform_layout_function = partition_params.transform_layout_function; + const CheckLoadCancellationFn& check_load_cancellation_fn = partition_params.check_load_cancellation_fn; do { // process full graph with each EP @@ -817,7 +895,8 @@ static Status PartitionOnnxFormatModel(const PartitionParams& partition_params, fused_kernel_registry, *ep, mode, fused_node_unique_id, transform_layout_function, partition_params.debug_graph_fn, - logger, resource_accountant)); + check_load_cancellation_fn, + logger, resource_accountant, graph_optimizer_registry)); } // expand any nodes that have an ONNX function definition but no matching ORT kernel. @@ -838,6 +917,7 @@ static Status PartitionOnnxFormatModel(const PartitionParams& partition_params, static Status PartitionOrtFormatModelImpl(const PartitionParams& partition_params, KernelRegistryManager& kernel_registry_mgr, IExecutionProvider& current_ep, + const GraphOptimizerRegistry& graph_optimizer_registry, const logging::Logger& logger) { // handle testing edge case where optimizers or constant lifting results in graph with no nodes. // doing it here saves all providers checking for this in GetCapability @@ -853,7 +933,7 @@ static Status PartitionOrtFormatModelImpl(const PartitionParams& partition_param PartitionParams subgraph_partition_params = partition_params; subgraph_partition_params.graph = std::ref(subgraph); ORT_RETURN_IF_ERROR(PartitionOrtFormatModelImpl(subgraph_partition_params, kernel_registry_mgr, - current_ep, logger)); + current_ep, graph_optimizer_registry, logger)); } } @@ -869,7 +949,9 @@ static Status PartitionOrtFormatModelImpl(const PartitionParams& partition_param std::cref(partition_params.transform_layout_function), std::cref(partition_params.debug_graph_fn), #endif // !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) - nullptr + nullptr, + std::ref(graph_optimizer_registry), + partition_params.check_load_cancellation_fn }; // clang-format on @@ -926,6 +1008,9 @@ static Status PartitionOrtFormatModelImpl(const PartitionParams& partition_param std::vector single_node_compute_func; ORT_RETURN_IF_ERROR(current_ep.Compile({IExecutionProvider::FusedNodeAndGraph{node, *compilation_entry.viewer}}, single_node_compute_func)); + if (partition_params.check_load_cancellation_fn()) { + return ORT_MAKE_STATUS(ONNXRUNTIME, MODEL_LOAD_CANCELED, "Graph partitioning is canceled due to user request."); + } ORT_RETURN_IF(single_node_compute_func.empty(), "single_node_compute_func should have 1 element."); auto& func_mgr = partition_params.func_mgr.get(); @@ -962,10 +1047,11 @@ static Status PartitionOrtFormatModelImpl(const PartitionParams& partition_param static Status PartitionOrtFormatModel(const PartitionParams& partition_params, const ExecutionProviders& execution_providers, KernelRegistryManager& kernel_registry_manager, + const GraphOptimizerRegistry& graph_optimizer_registry, const logging::Logger& logger) { // process full graph with each EP for (const auto& ep : execution_providers) { - ORT_RETURN_IF_ERROR(PartitionOrtFormatModelImpl(partition_params, kernel_registry_manager, *ep, logger)); + ORT_RETURN_IF_ERROR(PartitionOrtFormatModelImpl(partition_params, kernel_registry_manager, *ep, graph_optimizer_registry, logger)); } return Status::OK(); @@ -985,6 +1071,8 @@ Status GraphPartitioner::InlineFunctionsAOT(Model& model, return Status::OK(); } + auto check_load_cancellation_fn = [this]() -> bool { return IsLoadCancellationFlagSet(); }; + auto& graph = model.MainGraph(); InlinedHashSet not_inlined; do { @@ -992,14 +1080,15 @@ Status GraphPartitioner::InlineFunctionsAOT(Model& model, ORT_RETURN_IF_ERROR(InlineFunctionsAOTImpl(execution_providers, kernel_registry_manager, graph, + *graph_optimizer_registry_, logger, + check_load_cancellation_fn, not_inlined, inlined_count)); if (inlined_count == 0) { break; } - ORT_RETURN_IF_ERROR(graph.Resolve()); } while (true); @@ -1034,6 +1123,8 @@ Status GraphPartitioner::Partition(Graph& graph, FuncManager& func_mgr, return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "No provider specified."); } + CheckLoadCancellationFn check_load_cancellation_fn = [this]() -> bool { return IsLoadCancellationFlagSet(); }; + #if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) // fused_kernel_registry is preparing the kernels created on the fly for fused sub graph. // It is only visible for current session. @@ -1044,12 +1135,12 @@ Status GraphPartitioner::Partition(Graph& graph, FuncManager& func_mgr, PartitionParams partition_params{ std::ref(graph), + std::cref(check_load_cancellation_fn), std::ref(func_mgr), std::ref(*fused_kernel_registry), std::ref(fused_node_unique_id), std::cref(transform_layout_function), - std::cref(debug_graph_fn), - }; + std::cref(debug_graph_fn)}; #else // !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) @@ -1058,6 +1149,7 @@ Status GraphPartitioner::Partition(Graph& graph, FuncManager& func_mgr, ORT_UNUSED_PARAMETER(debug_graph_fn); PartitionParams partition_params{ std::ref(graph), + std::cref(check_load_cancellation_fn), }; #endif // !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) @@ -1068,7 +1160,8 @@ Status GraphPartitioner::Partition(Graph& graph, FuncManager& func_mgr, if (ep_context_enabled) { std::string ep_context_path = config_options.GetConfigOrDefault(kOrtSessionOptionEpContextFilePath, ""); // Check before EP compile graphs - ORT_RETURN_IF_ERROR(EpContextFilePathCheck(ep_context_path, graph.ModelPath())); + std::filesystem::path context_cache_path; + ORT_RETURN_IF_ERROR(GetValidatedEpContextPath(ep_context_path, graph.ModelPath(), context_cache_path)); } // We use this only if Resource Aware Partitioning is enabled for any of the EPs @@ -1077,7 +1170,7 @@ Status GraphPartitioner::Partition(Graph& graph, FuncManager& func_mgr, ORT_RETURN_IF_ERROR(NodeStatsRecorder::CreateAccountants(config_options, graph.ModelPath(), ep_acc_map)); ORT_RETURN_IF_ERROR(PartitionOnnxFormatModel(partition_params, mode, providers_, kernel_registry_mgr_, - ep_acc_map, logger)); + ep_acc_map, *graph_optimizer_registry_, logger)); if (ep_context_enabled) { std::string ep_context_path = config_options.GetConfigOrDefault(kOrtSessionOptionEpContextFilePath, ""); @@ -1091,7 +1184,7 @@ Status GraphPartitioner::Partition(Graph& graph, FuncManager& func_mgr, return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "ONNX models are not supported in this build."); #endif //! defined(ORT_MINIMAL_BUILD) } else { - ORT_RETURN_IF_ERROR(PartitionOrtFormatModel(partition_params, providers_, kernel_registry_mgr_, logger)); + ORT_RETURN_IF_ERROR(PartitionOrtFormatModel(partition_params, providers_, kernel_registry_mgr_, *graph_optimizer_registry_, logger)); } #if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) diff --git a/onnxruntime/core/framework/graph_partitioner.h b/onnxruntime/core/framework/graph_partitioner.h index d1ef193cf1520..87edc7a64c6b5 100644 --- a/onnxruntime/core/framework/graph_partitioner.h +++ b/onnxruntime/core/framework/graph_partitioner.h @@ -7,6 +7,7 @@ #include "core/graph/graph.h" #include "core/framework/fuse_nodes_funcs.h" #include "core/framework/transform_layout_functions.h" +#include "core/optimizer/graph_optimizer_registry.h" namespace onnxruntime { @@ -24,9 +25,22 @@ class GraphPartitioner { }; // The order of providers represents the user preference. - GraphPartitioner(KernelRegistryManager& kernel_registry_mgr, const ExecutionProviders& providers) + GraphPartitioner(KernelRegistryManager& kernel_registry_mgr, + const ExecutionProviders& providers, + std::unique_ptr graph_optimizer_registry) : kernel_registry_mgr_(kernel_registry_mgr), - providers_(providers) { + providers_(providers), + graph_optimizer_registry_(std::move(graph_optimizer_registry)) { + } + + GraphPartitioner(KernelRegistryManager& kernel_registry_mgr, + const ExecutionProviders& providers, + std::unique_ptr graph_optimizer_registry, + CheckLoadCancellationFn check_load_cancellation_fn) + : kernel_registry_mgr_(kernel_registry_mgr), + providers_(providers), + graph_optimizer_registry_(std::move(graph_optimizer_registry)), + check_load_cancellation_fn_(std::move(check_load_cancellation_fn)) { } // Run partitioning. @@ -37,6 +51,10 @@ class GraphPartitioner { Mode mode = Mode::kNormal, const layout_transformation::DebugGraphFn& debug_graph_fn = {}) const; + bool IsLoadCancellationFlagSet() const { + return check_load_cancellation_fn_ && check_load_cancellation_fn_(); + } + #ifndef ORT_MINIMAL_BUILD ///

// Ahead of Time Function inlining. The main purpose of the function is to inline as many @@ -64,6 +82,8 @@ class GraphPartitioner { KernelRegistryManager& kernel_registry_mgr_; const ExecutionProviders& providers_; + std::unique_ptr graph_optimizer_registry_; + CheckLoadCancellationFn check_load_cancellation_fn_; }; } // namespace onnxruntime diff --git a/onnxruntime/core/framework/model_metadef_id_generator.cc b/onnxruntime/core/framework/model_metadef_id_generator.cc index 4a35052d159a0..2d55aa8360bd2 100644 --- a/onnxruntime/core/framework/model_metadef_id_generator.cc +++ b/onnxruntime/core/framework/model_metadef_id_generator.cc @@ -28,7 +28,7 @@ int ModelMetadefIdGenerator::GenerateId(const onnxruntime::GraphViewer& graph_vi // hash the bytes in the Graph instance. we can't just use the address as a new Graph instance may use // the same memory (unit tests prove this can occur). the raw bytes of the Graph instance should be a unique // fingerprint for the instance that can use used as the key to the hash of the model path/contents. - MurmurHash3::x86_128(&main_graph, gsl::narrow_cast(sizeof(Graph)), instance_hash[0], &instance_hash); + MurmurHash3::x86_128(&main_graph, sizeof(Graph), instance_hash[0], &instance_hash); HashValue graph_instance_hash = instance_hash[0] | (uint64_t(instance_hash[1]) << 32); // if we've already hashed this main graph instance use the cached value @@ -42,10 +42,10 @@ int ModelMetadefIdGenerator::GenerateId(const onnxruntime::GraphViewer& graph_vi // this may not be available if the model was loaded from a stream or in-memory bytes const auto model_path_str = main_graph.ModelPath().string(); if (!model_path_str.empty()) { - MurmurHash3::x86_128(model_path_str.data(), gsl::narrow_cast(model_path_str.size()), hash[0], &hash); + MurmurHash3::x86_128(model_path_str.data(), model_path_str.size(), hash[0], &hash); } else { auto hash_str = [&hash](const std::string& str) { - MurmurHash3::x86_128(str.data(), gsl::narrow_cast(str.size()), hash[0], &hash); + MurmurHash3::x86_128(str.data(), str.size(), hash[0], &hash); }; // fingerprint the main graph by hashing graph inputs and the ordered outputs from each node diff --git a/onnxruntime/core/framework/murmurhash3.cc b/onnxruntime/core/framework/murmurhash3.cc index 802f0a4c58a6d..c984767932a3b 100644 --- a/onnxruntime/core/framework/murmurhash3.cc +++ b/onnxruntime/core/framework/murmurhash3.cc @@ -59,7 +59,7 @@ inline uint64_t rotl64(uint64_t x, int8_t r) { // // Changes to support big-endian from https://github.com/explosion/murmurhash/pull/27/ // were manually applied to original murmurhash3 source code. -ORT_FORCEINLINE uint32_t getblock32(const uint32_t* p, int i) { +ORT_FORCEINLINE uint32_t getblock32(const uint32_t* p, ptrdiff_t i) { if constexpr (onnxruntime::endian::native == onnxruntime::endian::little) { return p[i]; } else { @@ -71,7 +71,7 @@ ORT_FORCEINLINE uint32_t getblock32(const uint32_t* p, int i) { } } -ORT_FORCEINLINE uint64_t getblock64(const uint64_t* p, int i) { +ORT_FORCEINLINE uint64_t getblock64(const uint64_t* p, ptrdiff_t i) { if constexpr (onnxruntime::endian::native == onnxruntime::endian::little) { return p[i]; } else { @@ -115,10 +115,10 @@ ORT_FORCEINLINE constexpr uint64_t fmix64(uint64_t k) { //----------------------------------------------------------------------------- namespace onnxruntime { -void MurmurHash3::x86_32(const void* key, int len, +void MurmurHash3::x86_32(const void* key, size_t len, uint32_t seed, void* out) { const uint8_t* data = (const uint8_t*)key; - const int nblocks = len / 4; + const auto nblocks = static_cast(len / 4U); uint32_t h1 = seed; @@ -128,9 +128,9 @@ void MurmurHash3::x86_32(const void* key, int len, //---------- // body - const uint32_t* blocks = (const uint32_t*)(data + static_cast(nblocks) * 4); + const uint32_t* blocks = (const uint32_t*)(data + nblocks * 4); - for (int i = -nblocks; i; i++) { + for (auto i = -nblocks; i; i++) { uint32_t k1 = getblock32(blocks, i); k1 *= c1; @@ -145,7 +145,7 @@ void MurmurHash3::x86_32(const void* key, int len, //---------- // tail - const uint8_t* tail = (const uint8_t*)(data + static_cast(nblocks) * 4); + const uint8_t* tail = (const uint8_t*)(data + nblocks * 4); uint32_t k1 = 0; @@ -176,9 +176,9 @@ void MurmurHash3::x86_32(const void* key, int len, //----------------------------------------------------------------------------- -void MurmurHash3::x86_128(const void* key, int len, uint32_t seed, void* out) { +void MurmurHash3::x86_128(const void* key, size_t len, uint32_t seed, void* out) { const uint8_t* data = (const uint8_t*)key; - const int nblocks = len / 16; + const auto nblocks = static_cast(len / 16U); uint32_t h1 = seed; uint32_t h2 = seed; @@ -193,9 +193,9 @@ void MurmurHash3::x86_128(const void* key, int len, uint32_t seed, void* out) { //---------- // body - const uint32_t* blocks = (const uint32_t*)(data + static_cast(nblocks) * 16); + const uint32_t* blocks = (const uint32_t*)(data + nblocks * 16); - for (int i = -nblocks; i; i++) { + for (auto i = -nblocks; i; i++) { uint32_t k1 = getblock32(blocks, i * 4 + 0); uint32_t k2 = getblock32(blocks, i * 4 + 1); uint32_t k3 = getblock32(blocks, i * 4 + 2); @@ -241,7 +241,7 @@ void MurmurHash3::x86_128(const void* key, int len, uint32_t seed, void* out) { //---------- // tail - const uint8_t* tail = (const uint8_t*)(data + static_cast(nblocks) * 16); + const uint8_t* tail = (const uint8_t*)(data + nblocks * 16); uint32_t k1 = 0; uint32_t k2 = 0; diff --git a/onnxruntime/core/framework/murmurhash3.h b/onnxruntime/core/framework/murmurhash3.h index ab86a3e591adf..ddba725bb2a37 100644 --- a/onnxruntime/core/framework/murmurhash3.h +++ b/onnxruntime/core/framework/murmurhash3.h @@ -4,13 +4,14 @@ #pragma once #include +#include namespace onnxruntime { struct MurmurHash3 { // generate 32-bit hash from input and write to 'out' - static void x86_32(const void* key, int len, uint32_t seed, void* out); + static void x86_32(const void* key, size_t len, uint32_t seed, void* out); // generate 128-bit hash from input and write to 'out'. - static void x86_128(const void* key, int len, uint32_t seed, void* out); + static void x86_128(const void* key, size_t len, uint32_t seed, void* out); }; } // namespace onnxruntime diff --git a/onnxruntime/core/framework/onnxruntime_typeinfo.cc b/onnxruntime/core/framework/onnxruntime_typeinfo.cc index a884927abddb7..1c446840b7938 100644 --- a/onnxruntime/core/framework/onnxruntime_typeinfo.cc +++ b/onnxruntime/core/framework/onnxruntime_typeinfo.cc @@ -10,8 +10,8 @@ #include "core/framework/sparse_tensor.h" #include "core/graph/onnx_protobuf.h" #include "core/session/ort_apis.h" +#include "core/session/model_editor_api.h" #include "core/framework/error_code_helper.h" - #include "core/framework/tensor_type_and_shape.h" #include "core/framework/onnxruntime_map_type_info.h" #include "core/framework/onnxruntime_sequence_type_info.h" @@ -40,7 +40,7 @@ OrtTypeInfo::OrtTypeInfo(std::unique_ptr optional_type_info : type(ONNX_TYPE_OPTIONAL), optional_type_info(std::move(optional_type_info)) {} OrtTypeInfo::OrtTypeInfo(ONNXType type, std::unique_ptr data) noexcept - : type(type), data(std::move(data)) { + : type(type), tensor_type_info(std::move(data)) { } OrtTypeInfo::~OrtTypeInfo() = default; @@ -55,7 +55,9 @@ ORT_API_STATUS_IMPL(OrtApis::GetOnnxTypeFromTypeInfo, _In_ const struct OrtTypeI ORT_API_STATUS_IMPL(OrtApis::CastTypeInfoToTensorInfo, _In_ const struct OrtTypeInfo* input, _Outptr_result_maybenull_ const struct OrtTensorTypeAndShapeInfo** out) { API_IMPL_BEGIN - *out = (input->type == ONNX_TYPE_TENSOR || input->type == ONNX_TYPE_SPARSETENSOR) ? input->data.get() : nullptr; + *out = (input->type == ONNX_TYPE_TENSOR || input->type == ONNX_TYPE_SPARSETENSOR) + ? input->tensor_type_info.get() + : nullptr; return nullptr; API_IMPL_END } @@ -84,8 +86,8 @@ ORT_API_STATUS_IMPL(OrtApis::CastTypeInfoToOptionalTypeInfo, _In_ const OrtTypeI API_IMPL_END } -ORT_API_STATUS_IMPL(OrtApis::GetDenotationFromTypeInfo, _In_ const OrtTypeInfo* type_info, _Out_ const char** const out, - _Out_ size_t* len) { +ORT_API_STATUS_IMPL(OrtApis::GetDenotationFromTypeInfo, _In_ const OrtTypeInfo* type_info, + _Out_ const char** const out, _Out_ size_t* len) { API_IMPL_BEGIN *out = type_info->denotation.c_str(); *len = type_info->denotation.size(); @@ -93,6 +95,61 @@ ORT_API_STATUS_IMPL(OrtApis::GetDenotationFromTypeInfo, _In_ const OrtTypeInfo* API_IMPL_END } +#if !defined(ORT_MINIMAL_BUILD) +ORT_API_STATUS_IMPL(OrtModelEditorAPI::CreateTensorTypeInfo, _In_ const OrtTensorTypeAndShapeInfo* tensor_info, + _Out_ OrtTypeInfo** type_info) { + API_IMPL_BEGIN + auto ti = std::make_unique(ONNXType::ONNX_TYPE_TENSOR); + ti->tensor_type_info = tensor_info->Clone(); + *type_info = ti.release(); + return nullptr; + API_IMPL_END +} + +ORT_API_STATUS_IMPL(OrtModelEditorAPI::CreateSparseTensorTypeInfo, _In_ const OrtTensorTypeAndShapeInfo* tensor_info, + _Out_ OrtTypeInfo** type_info) { + API_IMPL_BEGIN + auto ti = std::make_unique(ONNXType::ONNX_TYPE_SPARSETENSOR); + ti->tensor_type_info = tensor_info->Clone(); + *type_info = ti.release(); + return nullptr; + API_IMPL_END +} + +ORT_API_STATUS_IMPL(OrtModelEditorAPI::CreateMapTypeInfo, ONNXTensorElementDataType map_key_type, + _In_ const OrtTypeInfo* map_value_type, _Out_ OrtTypeInfo** type_info) { + API_IMPL_BEGIN + auto ti = std::make_unique(ONNXType::ONNX_TYPE_MAP); + ti->map_type_info = std::make_unique(map_key_type, map_value_type->Clone()); + *type_info = ti.release(); + + return nullptr; + API_IMPL_END +} + +ORT_API_STATUS_IMPL(OrtModelEditorAPI::CreateSequenceTypeInfo, _In_ const OrtTypeInfo* sequence_type, + _Out_ OrtTypeInfo** type_info) { + API_IMPL_BEGIN + auto ti = std::make_unique(ONNXType::ONNX_TYPE_SEQUENCE); + ti->sequence_type_info = std::make_unique(sequence_type->Clone()); + *type_info = ti.release(); + + return nullptr; + API_IMPL_END +} + +ORT_API_STATUS_IMPL(OrtModelEditorAPI::CreateOptionalTypeInfo, _In_ const OrtTypeInfo* contained_type, + _Out_ OrtTypeInfo** type_info) { + API_IMPL_BEGIN + auto ti = std::make_unique(ONNXType::ONNX_TYPE_OPTIONAL); + ti->optional_type_info = std::make_unique(contained_type->Clone()); + *type_info = ti.release(); + + return nullptr; + API_IMPL_END +} +#endif // !defined(ORT_MINIMAL_BUILD) + ORT_API(void, OrtApis::ReleaseTypeInfo, _Frees_ptr_opt_ OrtTypeInfo* ptr) { std::unique_ptr p(ptr); } @@ -298,8 +355,8 @@ std::unique_ptr OrtTypeInfo::Clone() const { #endif case ONNX_TYPE_TENSOR: { std::unique_ptr info; - if (data) { - info = data->Clone(); + if (tensor_type_info) { + info = tensor_type_info->Clone(); } result = MakePtr(type, std::move(info)); result->denotation = denotation; diff --git a/onnxruntime/core/framework/onnxruntime_typeinfo.h b/onnxruntime/core/framework/onnxruntime_typeinfo.h index 72d263d5fa442..54bb946e0d36b 100644 --- a/onnxruntime/core/framework/onnxruntime_typeinfo.h +++ b/onnxruntime/core/framework/onnxruntime_typeinfo.h @@ -31,7 +31,7 @@ struct OrtTypeInfo { ONNXType type; std::string denotation; - std::unique_ptr data; + std::unique_ptr tensor_type_info; std::unique_ptr map_type_info; std::unique_ptr sequence_type_info; std::unique_ptr optional_type_info; diff --git a/onnxruntime/core/framework/prepacked_weights.cc b/onnxruntime/core/framework/prepacked_weights.cc index 6aee164dcf104..460b43f2888ab 100644 --- a/onnxruntime/core/framework/prepacked_weights.cc +++ b/onnxruntime/core/framework/prepacked_weights.cc @@ -11,14 +11,14 @@ HashValue PrePackedWeights::GetHash() const { uint32_t hash[4] = {0, 0, 0, 0}; - auto hash_int8_t_buffer = [&hash](void* data, int len) { MurmurHash3::x86_128(data, len, hash[0], &hash); }; + auto hash_int8_t_buffer = [&hash](void* data, size_t len) { MurmurHash3::x86_128(data, len, hash[0], &hash); }; ORT_ENFORCE(buffers_.size() == buffer_sizes_.size()); for (size_t iter = 0; iter < buffers_.size(); ++iter) { // some pre-packed buffers may be null if they were just "place-holders" occupying an index // in the "buffers_" vector if (buffers_[iter].get() != nullptr) { - hash_int8_t_buffer(buffers_[iter].get(), static_cast(buffer_sizes_[iter])); + hash_int8_t_buffer(buffers_[iter].get(), buffer_sizes_[iter]); } } diff --git a/onnxruntime/core/framework/resource_accountant.cc b/onnxruntime/core/framework/resource_accountant.cc index 17f1fd0c3898e..0665cc1951e60 100644 --- a/onnxruntime/core/framework/resource_accountant.cc +++ b/onnxruntime/core/framework/resource_accountant.cc @@ -147,8 +147,8 @@ static Status LoadNodeAllocationStats( size_t initializers_sizes = SafeInt(std::stoull(std::string{splits[2]})); size_t total_dynamic_sizes = SafeInt(std::stoull(std::string{splits[3]})); size_t total_temp_allocations = SafeInt(std::stoull(std::string{splits[4]})); - node_stats.insert_or_assign(std::move(node_name), {input_sizes, initializers_sizes, - total_dynamic_sizes, total_temp_allocations}); + const NodeAllocationStats stats = {input_sizes, initializers_sizes, total_dynamic_sizes, total_temp_allocations}; + node_stats.insert_or_assign(std::move(node_name), stats); } result.swap(node_stats); @@ -204,7 +204,7 @@ std::string IResourceAccountant::MakeUniqueNodeName(const Node& node) { uint32_t hash[4] = {0, 0, 0, 0}; auto hash_str = [&hash](const std::string& str) { - MurmurHash3::x86_128(str.data(), narrow(str.size()), hash[0], &hash); + MurmurHash3::x86_128(str.data(), str.size(), hash[0], &hash); }; const auto& node_name = (node.Name().empty()) ? node.OpType() : node.Name(); @@ -224,4 +224,4 @@ std::string IResourceAccountant::MakeUniqueNodeName(const Node& node) { return result; } -} // namespace onnxruntime \ No newline at end of file +} // namespace onnxruntime diff --git a/onnxruntime/core/framework/session_options.h b/onnxruntime/core/framework/session_options.h index 8d4db36106f28..ef323b99b006c 100644 --- a/onnxruntime/core/framework/session_options.h +++ b/onnxruntime/core/framework/session_options.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "core/common/inlined_containers.h" #include "core/framework/config_options.h" @@ -66,6 +67,8 @@ struct FreeDimensionOverride { int64_t dim_value; }; +using CheckLoadCancellationFn = std::function; + /** * Configuration information for a session. */ @@ -184,6 +187,18 @@ struct SessionOptions { // User specified logging func and param OrtLoggingFunction user_logging_function = nullptr; void* user_logging_param = nullptr; + + void SetLoadCancellationFlag(bool value) noexcept { + *load_cancellation_flag = value; + } + + bool IsLoadCancellationFlagSet() const noexcept { + return *load_cancellation_flag; + } + + // Load cancellation flag is necessary to be within shared memory as session_options are + // copied internally and the flag needs to be accessible across all copies. + std::shared_ptr load_cancellation_flag = std::make_shared(false); }; inline std::ostream& operator<<(std::ostream& os, const SessionOptions& session_options) { diff --git a/onnxruntime/core/framework/session_state.cc b/onnxruntime/core/framework/session_state.cc index 27aa4f38a4ec9..6362a3169f3a3 100644 --- a/onnxruntime/core/framework/session_state.cc +++ b/onnxruntime/core/framework/session_state.cc @@ -54,11 +54,24 @@ class StreamCommandHandleRegistryImpl : public IStreamCommandHandleRegistry { create_stream_map_.insert({device_type, f}); } + void RegisterSetDeviceFn(const OrtDevice::DeviceType device_type, SetDeviceFn f) override { + set_device_map_.insert({device_type, f}); + } + + std::optional GetSetDeviceFn(const OrtDevice::DeviceType device_type) const override { + auto it = set_device_map_.find(device_type); + if (it != set_device_map_.end()) { + return it->second; + } + return std::nullopt; + } + StreamCommandHandleRegistryImpl() = default; private: InlinedHashMap notification_wait_map_; InlinedHashMap create_stream_map_; + InlinedHashMap set_device_map_; }; #endif @@ -409,6 +422,10 @@ Status SessionState::PrepackConstantInitializedTensors( auto prepacked_constant_weights = [this, &constant_initializers_use_count, &initializers_to_share_map]( bool should_cache_prepacked_weights_for_shared_initializers) -> Status { for (auto& node : GetGraphViewer().Nodes()) { + if (sess_options_.IsLoadCancellationFlagSet()) { + return ORT_MAKE_STATUS(ONNXRUNTIME, MODEL_LOAD_CANCELED, + "Weight pre-packing was canceled due to user request."); + } auto kernel = GetMutableKernel(node.Index()); int input_idx = 0; for (auto& input_def : node.InputDefs()) { @@ -1127,7 +1144,7 @@ Status SessionState::CreateSubgraphSessionState() { if (!ep.empty() && ep != kCpuExecutionProvider && ep != kCudaExecutionProvider && ep != kRocmExecutionProvider && ep != kDmlExecutionProvider && - ep != kJsExecutionProvider) { + ep != kJsExecutionProvider && ep != kWebGpuExecutionProvider) { // SessionState is only used when ORT is executing the subgraph. If a non-ORT EP has taken the control flow // node containing the subgraph it will create whatever state it needs internally. continue; @@ -1528,6 +1545,11 @@ Status SessionState::FinalizeSessionStateImpl(const std::basic_string(&tensor_proto), ext_data_buf, ext_data_len); + } + } // NB: creating a do-nothing allocator per tensor is wasteful; can perhaps be // avoided if the Tensor class implements the do-nothing behavior when given a @@ -203,13 +208,12 @@ static common::Status DeserializeTensorProto(const Env& env, const std::basic_st } } -common::Status AllocateTensor( - const onnxruntime::MemBuffer* m, - std::unique_ptr& p_tensor, - const onnxruntime::DataTypeImpl* const& type, - onnxruntime::TensorShape& tensor_shape, - bool use_device_allocator_for_initializers, - const onnxruntime::AllocatorPtr& alloc) { +common::Status AllocateTensor(const onnxruntime::MemBuffer* m, + std::unique_ptr& p_tensor, + const onnxruntime::DataTypeImpl* const& type, + onnxruntime::TensorShape& tensor_shape, + bool use_device_allocator_for_initializers, + const onnxruntime::AllocatorPtr& alloc) { if (m != nullptr) { p_tensor = std::make_unique(type, tensor_shape, m->GetBuffer(), m->GetAllocInfo()); if (m->GetLen() < p_tensor->SizeInBytes()) { @@ -354,6 +358,7 @@ common::Status SaveInitializedTensors( } ORT_RETURN_IF_ERROR(planner.Trace(entry.first, entry.second)); } + // 2. allocate weight buffer on different locations // planned_initializers_memory_size_in_byte is not actual physical size. // It's the virtual size computed by planner. @@ -373,6 +378,12 @@ common::Status SaveInitializedTensors( // 3. create weight tensors based on weights buffer for (const auto& entry : id_to_initialized_tensor) { + // We check for cancellation for every initializer since mapping from disk can be costly + if (session_options.IsLoadCancellationFlagSet()) { + return ORT_MAKE_STATUS(ONNXRUNTIME, MODEL_LOAD_CANCELED, + "Saving session state weights is canceled due to user request."); + } + int ort_value_index = entry.first; const std::string& name = entry.second->name(); @@ -386,6 +397,9 @@ common::Status SaveInitializedTensors( if (user_supplied_initializer_ids.find(entry.first) != user_supplied_initializer_ids.end()) { ort_value = *(session_options.initializers_to_share_map.at(name)); LOGS(logger, INFO) << "Using user supplied initializer with name (" << name << ")."; + + } else if (graph.GetOrtValueInitializer(name, ort_value)) { + // populated OrtValue from the Graph instance } else { const ONNX_NAMESPACE::TensorProto& tensor_proto = *(entry.second); @@ -397,10 +411,9 @@ common::Status SaveInitializedTensors( session_options.config_options.GetConfigOrDefault(kOrtSessionOptionsUseDeviceAllocatorForInitializers, "0") == "1"; Tensor* p_tensor = nullptr; - if (auto iter = buffered_tensors.find(name); - iter != buffered_tensors.end()) { - p_tensor = iter->second.release(); - buffered_tensors.erase(iter); + auto buffered_tensors_iter = buffered_tensors.find(name); + if (buffered_tensors_iter != buffered_tensors.end()) { + p_tensor = buffered_tensors_iter->second.get(); } Status st = DeserializeTensorProto(env, graph_loc, tensor_proto, (m.has_value()) ? &*m : nullptr, alloc, @@ -412,6 +425,12 @@ common::Status SaveInitializedTensors( oss << "Deserialize tensor " << name << " failed." << st.ErrorMessage(); return Status(st.Category(), st.Code(), oss.str()); } + + if (p_tensor != nullptr) { + // p_tensor was wrapped in a deleter by DeserializeTensorProto so we can simply release it here. + ORT_IGNORE_RETURN_VALUE(buffered_tensors_iter->second.release()); + buffered_tensors.erase(buffered_tensors_iter); + } } // 'name' is a reference to a string within the TensorProto that save_tensor_func may free diff --git a/onnxruntime/core/framework/stream_execution_context.cc b/onnxruntime/core/framework/stream_execution_context.cc index dd7f4d35b34bd..e8beb98749028 100644 --- a/onnxruntime/core/framework/stream_execution_context.cc +++ b/onnxruntime/core/framework/stream_execution_context.cc @@ -205,6 +205,21 @@ void RunSince(size_t stream_idx, StreamExecutionContext& ctx, SessionScope& sess end = std::min(end, range->stream_pc_range[stream_idx].second); #endif +#ifdef ORT_ENABLE_STREAM + // If the device stream has corresponding SetDevice function registered, it means GPU device should be properly set to the correct device. + // The reason SetDevice should be called here is: + // - RunSince function can be invoked from a new thread + // - new threads default to using device 0, but the session may be tightly bound to a device > 0. + auto device_stream = ctx.GetDeviceStream(stream_idx); + if (device_stream) { + auto set_device_fn = ctx.GetSessionState().GetStreamHandleRegistryInstance().GetSetDeviceFn(device_stream->GetDevice().Type()); + if (set_device_fn.has_value()) { + auto device_id = device_stream->GetDevice().Id(); + set_device_fn.value()(device_id); + } + } +#endif + while (since < end) { if (!ctx.TaskStatus().IsOK()) { ctx.CompleteTask(); diff --git a/onnxruntime/core/framework/tensor_type_and_shape.cc b/onnxruntime/core/framework/tensor_type_and_shape.cc index 418e46924fb9f..9bbea279da82d 100644 --- a/onnxruntime/core/framework/tensor_type_and_shape.cc +++ b/onnxruntime/core/framework/tensor_type_and_shape.cc @@ -49,10 +49,27 @@ ORT_API_STATUS_IMPL(OrtApis::SetTensorElementType, _Inout_ OrtTensorTypeAndShape API_IMPL_END } -ORT_API_STATUS_IMPL(OrtApis::SetDimensions, OrtTensorTypeAndShapeInfo* this_ptr, +ORT_API_STATUS_IMPL(OrtApis::SetDimensions, OrtTensorTypeAndShapeInfo* info, _In_ const int64_t* dim_values, size_t dim_count) { API_IMPL_BEGIN - this_ptr->shape = onnxruntime::TensorShape(dim_values, dim_count); + if (std::any_of(dim_values, dim_values + dim_count, [](int64_t v) { return v < -1; })) { + return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, "dim_values must be -1 (symbolic dimension) or larger."); + } + + auto num_dims = std::max(dim_count, info->dim_params.size()); + + // make shape and dim_values consistent + info->dim_params.resize(num_dims, ""); + + onnxruntime::TensorShapeVector dims; + dims.resize(num_dims, -1); + + for (size_t idx = 0; idx < dim_count; ++idx) { + dims[idx] = dim_values[idx]; + } + + info->shape = onnxruntime::TensorShape(dims); + return nullptr; API_IMPL_END } @@ -88,10 +105,22 @@ ORT_API_STATUS_IMPL(OrtApis::GetSymbolicDimensions, ORT_API_STATUS_IMPL(OrtApis::SetSymbolicDimensions, _In_ struct OrtTensorTypeAndShapeInfo* info, _In_ const char** names, _In_ size_t dim_params_length) { + auto num_dims = std::max(info->shape.NumDimensions(), dim_params_length); + + // make shape and dim_values consistent + if (num_dims > info->shape.NumDimensions()) { + auto dim_values = info->shape.AsShapeVector(); + dim_values.resize(num_dims, -1); + info->shape = onnxruntime::TensorShape(dim_values); + } + info->dim_params.clear(); + info->dim_params.resize(num_dims, ""); + for (size_t idx = 0; idx < dim_params_length; ++idx) { - info->dim_params.push_back(names[idx]); + info->dim_params[idx] = names[idx]; } + return nullptr; } diff --git a/onnxruntime/core/framework/tensorprotoutils.cc b/onnxruntime/core/framework/tensorprotoutils.cc index 17c37b8882168..94a2a6677358e 100644 --- a/onnxruntime/core/framework/tensorprotoutils.cc +++ b/onnxruntime/core/framework/tensorprotoutils.cc @@ -270,10 +270,15 @@ void SetRawDataInTensorProto(ONNX_NAMESPACE::TensorProto& tensor_proto, std::str tensor_proto.set_raw_data(std::move(param)); } -void ConvertRawDataInTensorProto(TensorProto* tensor) { +void ConvertRawDataInTensorProto(TensorProto* tensor, + void* ext_data_buf, + size_t ext_data_len) { size_t element_size = 1; char* bytes = NULL; size_t num_elements = 0; + if (ext_data_buf && !ext_data_len) { + return; + } switch (tensor->data_type()) { case TensorProto_DataType_FLOAT: bytes = reinterpret_cast(tensor->mutable_float_data()->mutable_data()); @@ -337,6 +342,15 @@ void ConvertRawDataInTensorProto(TensorProto* tensor) { num_elements = (tensor->raw_data().size()) / element_size; bytes = const_cast(tensor->mutable_raw_data()->c_str()); } + + if (element_size == 1) { + return; + } + if (ext_data_buf) { + ORT_ENFORCE(ext_data_len % element_size == 0); + num_elements = ext_data_len / element_size; + bytes = reinterpret_cast(ext_data_buf); + } for (size_t i = 0; i < num_elements; ++i) { char* start_byte = bytes + i * element_size; char* end_byte = start_byte + element_size - 1; @@ -1317,22 +1331,15 @@ ONNX_NAMESPACE::TensorProto TensorToTensorProto(const Tensor& tensor, const auto* raw_data = tensor.DataRaw(); ORT_ENFORCE(raw_data, "Missing raw data for tensor proto. Invalid tensor."); static_assert(sizeof(void*) <= sizeof(ExternalDataInfo::OFFSET_TYPE)); - tensor_proto.set_data_location(ONNX_NAMESPACE::TensorProto_DataLocation_EXTERNAL); // we reinterpret_cast this back to void* in tensorprotoutils.cc:GetExtDataFromTensorProto. // use intptr_t as OFFSET_TYPE is signed. in theory you could get a weird looking value if the address uses the // high bit, but that should be unlikely in a scenario where we care about memory usage enough to use this path. auto offset = narrow(reinterpret_cast(raw_data)); - ONNX_NAMESPACE::StringStringEntryProto* entry = tensor_proto.mutable_external_data()->Add(); - entry->set_key("location"); - entry->set_value(ToUTF8String(onnxruntime::utils::kTensorProtoMemoryAddressTag)); - entry = tensor_proto.mutable_external_data()->Add(); - entry->set_key("offset"); - entry->set_value(std::to_string(offset)); - entry = tensor_proto.mutable_external_data()->Add(); - entry->set_key("length"); - entry->set_value(std::to_string(tensor.SizeInBytes())); + ExternalDataInfo::SetExternalLocationToProto(onnxruntime::utils::kTensorProtoMemoryAddressTag, + offset, tensor.SizeInBytes(), tensor_proto); + } else { utils::SetRawDataInTensorProto(tensor_proto, tensor.DataRaw(), tensor.SizeInBytes()); } diff --git a/onnxruntime/core/framework/tensorprotoutils.h b/onnxruntime/core/framework/tensorprotoutils.h index f5dec7ae988f2..79eae48c10411 100644 --- a/onnxruntime/core/framework/tensorprotoutils.h +++ b/onnxruntime/core/framework/tensorprotoutils.h @@ -41,12 +41,18 @@ Status GetExternalDataInfo(const ONNX_NAMESPACE::TensorProto& tensor_proto, ExternalDataInfo::PrepackedInfos* prepacked_infos = nullptr); /** * This function is used to convert the endianess of Tensor data. + * If ext_data_buf is provided, then this buffer content's endianess + * will be changed. * Mostly, will be used in big endian system to support the model file * generated on little endian system. - * @param initializer given initializer tensor + * @param tensor_proto given initializer tensor + * @param ext_data_buf optional externl data buffer + * @param ext_data_len optional externl data buffer lengeh * @returns None */ -void ConvertRawDataInTensorProto(ONNX_NAMESPACE::TensorProto* initializer); +void ConvertRawDataInTensorProto(ONNX_NAMESPACE::TensorProto* tensor_proto, + void* ext_data_buf = NULL, + size_t ext_data_len = 0); /** * Wrapper function for set_raw_data. diff --git a/onnxruntime/core/graph/contrib_ops/bert_defs.cc b/onnxruntime/core/graph/contrib_ops/bert_defs.cc index ecc8cb091b1b6..abfd93e13ca3b 100644 --- a/onnxruntime/core/graph/contrib_ops/bert_defs.cc +++ b/onnxruntime/core/graph/contrib_ops/bert_defs.cc @@ -207,7 +207,8 @@ void MultiHeadAttentionTypeAndShapeInference(ONNX_NAMESPACE::InferenceContext& c } auto past_present_share_buffer = getAttribute(ctx, "past_present_share_buffer", 0); - if (past_present_share_buffer) { + bool mha_buffer_sharing = hasInputShape(ctx, 6) && hasInputShape(ctx, 8); // equal to MHA op's definition for past_present_share_buffer + if (past_present_share_buffer || mha_buffer_sharing) { propagateElemTypeFromInputToOutput(ctx, past_key_index, 1); propagateElemTypeFromInputToOutput(ctx, static_cast(past_key_index) + 1, 2); } else { @@ -308,6 +309,29 @@ void BaseGroupQueryAttentionTypeAndShapeInference(ONNX_NAMESPACE::InferenceConte // shape of present key/value is (batch_size, kv_num_heads, total_sequence_length, head_size) present_shape.mutable_dim(2)->set_dim_value(total_sequence_length); + updateOutputShape(ctx, 1, present_shape); + updateOutputShape(ctx, 2, present_shape); + } + } else if (use_max_past_present_buffer == -1) { + const auto* total_sequence_length_data = ctx.getInputData(6); + if (total_sequence_length_data != nullptr && past_dims[2].has_dim_value()) { + int64_t total_sequence_length_value = 0; + const auto& data = ParseData(total_sequence_length_data); + total_sequence_length_value = static_cast(data[0]); + + // present_sequence_length = max(past_sequence_length, total_sequence_length) + int64_t present_sequence_length = total_sequence_length_value > past_dims[2].dim_value() + ? total_sequence_length_value + : past_dims[2].dim_value(); + + ONNX_NAMESPACE::TensorShapeProto present_shape; + for (auto& dim : past_dims) { + *present_shape.add_dim() = dim; + } + + // shape of present key/value is (batch_size, kv_num_heads, present_sequence_length, head_size) + present_shape.mutable_dim(2)->set_dim_value(present_sequence_length); + updateOutputShape(ctx, 1, present_shape); updateOutputShape(ctx, 2, present_shape); } @@ -879,7 +903,7 @@ ONNX_MS_OPERATOR_SET_SCHEMA( "past state for key with shape (batch_size, num_heads, past_sequence_length, head_size) for self attention" "When past_present_share_buffer is set, " "its shape is (batch_size, num_heads, max_sequence_length, head_size). " - // The re-ordering happens only for CUDA EP at the moment. We probably shall support 4 or 5D shape or + // The re-ordering happens only for CUDA EP at the moment. We probably shall support 4D or 5D shape or // attribute to distinguish whether it is re-ordered or not. "The keys buffer is re-ordered in such a way that its virtual sub-tensor of shape " "(batch_size, num_heads, max_sequence_length, head_size) which may be perceived as being of shape " @@ -940,12 +964,14 @@ ONNX_MS_OPERATOR_SET_SCHEMA( .Output(3, "qk", "normalized Q * K, of shape (batch_size, num_heads, 1, total_sequence_length). ", - "V", + "QK", OpSchema::Optional) - .TypeConstraint("V", {"tensor(float)"}, "Constrain qk output types to float32 tensors.") .TypeConstraint("T", {"tensor(float)", "tensor(float16)"}, "Constrain input and output types to float tensors.") + .TypeConstraint("QK", + {"tensor(float)", "tensor(float16)"}, + "Constrain QK output to float32 or float16 tensors, independent of input type or output type.") .TypeConstraint("M", {"tensor(int32)"}, "Constrain mask index to integer types") @@ -1010,31 +1036,50 @@ ONNX_MS_OPERATOR_SET_SCHEMA( OpSchema::Optional) .Input(6, "past_key", - "past state for self attention key with shape (batch_size, num_heads, past_sequence_length, head_size)", + "past state for key with shape (batch_size, num_heads, past_sequence_length, head_size) " + "or (batch_size, num_heads, max_sequence_length, head_size) when buffer sharing is used", "T", OpSchema::Optional) .Input(7, "past_value", - "past state for self attention value with shape (batch_size, num_heads, past_sequence_length, head_size)", + "past state for value with shape (batch_size, num_heads, past_sequence_length, head_size) " + "or (batch_size, num_heads, max_sequence_length, head_size) when buffer sharing is used", "T", OpSchema::Optional) + .Input(8, + "past_sequence_length", + "The past_sequence_length buffer sharing is used with", + "M", + OpSchema::Optional) + .Input(9, + "cache_indirection", + "A buffer of shape [batch_size, beam_width, max_sequence_length] where an [i, j, k] entry specifies" + "which beam the 'k' th token came from for the 'j' th beam for batch 'i' in the current iteration", + "M", + OpSchema::Optional) .Output(0, "output", "3D output tensor with shape (batch_size, sequence_length, v_hidden_size)", "T") .Output(1, "present_key", - "present state for cross attention key with shape (batch_size, num_heads, kv_sequence_length, head_size)" - "or present state for self attention key with shape (batch_size, num_heads, total_sequence_length, head_size)", + "present state for key with shape (batch_size, num_heads, total_sequence_length, head_size) " + "or (batch_size, num_heads, max_sequence_length, head_size) when buffer sharing is used", "T", OpSchema::Optional) .Output(2, "present_value", - "present state for cross attention value with shape (batch_size, num_heads, kv_sequence_length, head_size)" - "or present state for self attention value with shape (batch_size, num_heads, total_sequence_length, head_size)", + "present state for value with shape (batch_size, num_heads, total_sequence_length, head_size) " + "or (batch_size, num_heads, max_sequence_length, head_size) when buffer sharing is used", "T", OpSchema::Optional) + .Output(3, + "qk", + "normalized Q * K, of shape (batch_size, num_heads, sequence_length, total_sequence_length). ", + "QK", + OpSchema::Optional) .TypeConstraint("T", {"tensor(float)", "tensor(float16)"}, "Constrain input and output to float tensors.") + .TypeConstraint("QK", {"tensor(float)", "tensor(float16)"}, "Constrain QK output to float32 or float16 tensors, independent of input type or output type.") .TypeConstraint("M", {"tensor(int32)"}, "Constrain mask to integer types") .TypeAndShapeInferenceFunction([](ONNX_NAMESPACE::InferenceContext& ctx) { MultiHeadAttentionTypeAndShapeInference(ctx, 6); @@ -1128,6 +1173,17 @@ ONNX_MS_OPERATOR_SET_SCHEMA( "2D tensor with shape (max_sequence_length, head_size / 2).", "T", OpSchema::Optional) + .Input(9, + "position_ids", + "2D tensor with shape (batch_size, sequence_length). When processing the first prompt the kernel " + "uses only the first element", + "tensor(int64)", + OpSchema::Optional) + .Input(10, + "attention_bias", + "additional add to QxK' with shape (batch_size or 1, num_heads or 1, sequence_length, total_sequence_length)", + "T", + OpSchema::Optional) .Output(0, "output", "3D output tensor with shape (batch_size, sequence_length, hidden_size)", diff --git a/onnxruntime/core/graph/contrib_ops/contrib_defs.cc b/onnxruntime/core/graph/contrib_ops/contrib_defs.cc index e45787299f3ad..d87688a62040c 100644 --- a/onnxruntime/core/graph/contrib_ops/contrib_defs.cc +++ b/onnxruntime/core/graph/contrib_ops/contrib_defs.cc @@ -3361,7 +3361,8 @@ void RegisterContribSchemas() { OpSchema::NonDifferentiable) .TypeConstraint( "T", - {"tensor(int8)", + {"tensor(bool)", + "tensor(int8)", "tensor(int16)", "tensor(int32)", "tensor(int64)", @@ -3570,10 +3571,11 @@ GatherBlockQuantized is a Gather with data quantized. It is similar to Gather (h 1. Input `data` is a constant. It is quantized block-wise along attribute `quantize_axis` with block size specified by attribute `block_size`. `block_size must` be a power of 2 and not smaller than 16, like 16, 32, 64, 128, .. 2. Input `data`'s scale and zero point are specified by input `scales` and `zero_points`. `scales` and `zero_points` are also constants. - If `zero_points` is not provided, 0 is the zero point. + If `zero_points` is not provided, 0 is the zero point except when data is uint8 type then the default zero point is 8. 3. During the op execution, `data` and `indices` are first used to generate the quantized output. Then, `scales` and `zero_points` are used to dequantize the output. 4. The `output` and `scales` have the same type. The `data` and `zero_points` have the same type. + 5. For uint8 data, the `gather_axis` must be 0. )DOC"; ONNX_CONTRIB_OPERATOR_SCHEMA(GatherBlockQuantized) @@ -3601,7 +3603,7 @@ GatherBlockQuantized is a Gather with data quantized. It is similar to Gather (h .Input(2, "scales", "quantization scale", "T2") .Input(3, "zero_points", "quantization zero points", "T1", OpSchema::Optional) .Output(0, "output", "Dequantized output tensor of rank q + (r - 1).", "T2") - .TypeConstraint("T1", {"tensor(int4)", "tensor(uint4)"}, "Constrain quantized types.") + .TypeConstraint("T1", {"tensor(int4)", "tensor(uint4)", "tensor(uint8)"}, "Constrain quantized types.") .TypeConstraint("T2", {"tensor(float)", "tensor(float16)", "tensor(bfloat16)"}, "Constrain dequantized types.") .TypeConstraint("Tind", {"tensor(int32)", "tensor(int64)"}, "Constrain indices to integer types.") .TypeAndShapeInferenceFunction([](ONNX_NAMESPACE::InferenceContext& ctx) { @@ -3636,14 +3638,19 @@ GatherBlockQuantized is a Gather with data quantized. It is similar to Gather (h gather_axis = (gather_axis + r) % r; quantize_axis = (quantize_axis + r) % r; + if ((ctx.getInputType(0)->tensor_type().elem_type() == onnx::TensorProto_DataType_UINT8) && gather_axis != 0) { + fail_shape_inference("gather_axis must be 0, for uint8 data"); + } + if (scales_shape.dim_size() != r) { fail_shape_inference("scales must have the same rank as data"); } + uint32_t components = ctx.getInputType(0)->tensor_type().elem_type() == onnx::TensorProto_DataType_UINT8 ? 2 : 1; for (int i = 0; i < r; ++i) { if (!data_shape.dim(i).has_dim_value() || !scales_shape.dim(i).has_dim_value() || - (i == quantize_axis && (data_shape.dim(i).dim_value() + block_size - 1) / block_size != scales_shape.dim(i).dim_value()) || + (i == quantize_axis && (data_shape.dim(i).dim_value() * components + block_size - 1) / block_size != scales_shape.dim(i).dim_value()) || (i != quantize_axis && data_shape.dim(i).dim_value() != scales_shape.dim(i).dim_value())) { fail_shape_inference("data shape and scales shape do not match"); } @@ -3651,6 +3658,10 @@ GatherBlockQuantized is a Gather with data quantized. It is similar to Gather (h // validate zero point shape if (ctx.hasInput(3)) { + if (ctx.getInputType(0)->tensor_type().elem_type() == onnx::TensorProto_DataType_UINT8) { + fail_type_inference("zero_points are not supported for uint8_t data type"); + } + if (!hasInputShape(ctx, 3)) { fail_shape_inference("zero_points shape must be known"); } @@ -3674,12 +3685,15 @@ GatherBlockQuantized is a Gather with data quantized. It is similar to Gather (h ctx.getOutputType(0)->mutable_tensor_type()->mutable_shape(); } for (int i = 0; i < out_rank; ++i) { + // For uint8_t data type the last dimension needs to be expanded back to actual dimension, + // because the data 2 int4s are stored packed in a single uint8_t. + auto last_dimension_components = (i == out_rank - 1) ? components : 1; *ctx.getOutputType(0)->mutable_tensor_type()->mutable_shape()->add_dim() = (i < gather_axis) ? data_shape.dim(i) : (i >= gather_axis && i < gather_axis + q) ? indices_shape.dim(i - gather_axis) - : data_shape.dim(i - q + 1); + : data_shape.dim(i - q + 1) * last_dimension_components; } }); diff --git a/onnxruntime/core/graph/graph.cc b/onnxruntime/core/graph/graph.cc index e4915616b7b7c..334ecb3887d14 100644 --- a/onnxruntime/core/graph/graph.cc +++ b/onnxruntime/core/graph/graph.cc @@ -7,30 +7,34 @@ #include #include #include -#include #include +#include -#include "core/common/common.h" #include + +#include "core/common/common.h" #include "core/common/inlined_containers.h" #include "core/common/logging/logging.h" #include "core/common/narrow.h" #include "core/flatbuffers/flatbuffers_utils.h" +#include "core/framework/tensor_type_and_shape.h" #include "core/flatbuffers/schema/ort.fbs.h" -#include "core/framework/tensor_shape.h" #include "core/framework/tensor_external_data_info.h" +#include "core/framework/tensor_shape.h" +#include "core/framework/tensor_type_and_shape.h" #include "core/framework/tensorprotoutils.h" #include "core/framework/utils.h" +#include "core/graph/function_utils.h" #include "core/graph/graph_flatbuffers_utils.h" #include "core/graph/graph_viewer.h" #include "core/graph/indexed_sub_graph.h" #include "core/graph/model.h" +#include "core/graph/model_editor_api_types.h" #include "core/graph/model_load_utils.h" #include "core/graph/model_saving_options.h" #include "core/graph/node_attr_utils.h" #include "core/graph/op.h" #include "core/graph/runtime_optimization_record_container.h" -#include "core/graph/function_utils.h" #if !defined(ORT_MINIMAL_BUILD) #include "core/graph/function.h" @@ -1264,6 +1268,10 @@ Graph::Graph(const Model& owning_model, #endif } + if (owning_model_.IsLoadCancellationFlagSet()) { + ORT_THROW_WITH_CATEGORY_AND_CODE(ONNXRUNTIME, MODEL_LOAD_CANCELED, "Graph loading canceled due to user request."); + } + // Remove constant nodes as they're replaced with initializers above. const gsl::not_null*> graph_mutable_nodes{graph_proto_->mutable_node()}; graph_mutable_nodes->erase( @@ -1361,6 +1369,10 @@ Graph::Graph(const Model& owning_model, } } + if (owning_model_.IsLoadCancellationFlagSet()) { + ORT_THROW_WITH_CATEGORY_AND_CODE(ONNXRUNTIME, MODEL_LOAD_CANCELED, "Graph loading canceled due to user request."); + } + for (auto& graph_output : graph_proto_->output()) { if (utils::HasName(graph_output) && utils::HasType(graph_output)) { auto& name = graph_output.name(); @@ -3500,6 +3512,10 @@ void Graph::RemoveInitializedTensor(const std::string& tensor_name) { #if !defined(DISABLE_SPARSE_TENSORS) sparse_tensor_names_.erase(tensor_name); #endif + + // doesn't matter if it existed or not + ORT_IGNORE_RETURN_VALUE(ortvalue_initializers_.erase(tensor_name)); + SetGraphResolveNeeded(); } else { #if !defined(DISABLE_SPARSE_TENSORS) @@ -3631,8 +3647,8 @@ Status Graph::InjectExternalInitializersFromFilesInMemory( return Status::OK(); } -#endif // DISABLE_EXTERNAL_INITIALIZERS +#endif // DISABLE_EXTERNAL_INITIALIZERS #endif // !defined(ORT_MINIMAL_BUILD) bool Graph::GetInitializedTensor(const std::string& tensor_name, const TensorProto*& value) const { @@ -3645,6 +3661,16 @@ bool Graph::GetInitializedTensor(const std::string& tensor_name, const TensorPro return true; } +bool Graph::GetOrtValueInitializer(const std::string& name, OrtValue& value) const { + auto it = ortvalue_initializers_.find(name); + if (it == ortvalue_initializers_.end()) { + return false; + } + + value = it->second; + return true; +} + void Graph::CleanAllInitializedTensors() noexcept { name_to_initial_tensor_.clear(); #if !defined(DISABLE_SPARSE_TENSORS) @@ -3660,6 +3686,8 @@ void Graph::CleanAllInitializedTensors() noexcept { delete graph_proto_->mutable_initializer()->ReleaseCleared(); } #endif + + ortvalue_initializers_.clear(); } const ONNX_NAMESPACE::TensorProto* Graph::GetConstantInitializer(const std::string& initializer_name, @@ -3709,13 +3737,14 @@ void Graph::AddValueInfo(const NodeArg* new_value_info) { value_info_.insert(new_value_info); } -std::vector Graph::CreateNodeArgs(const google::protobuf::RepeatedPtrField& names, +template +std::vector Graph::CreateNodeArgs(const StringRange& names, const ArgNameToTypeMap& name_to_type_map) { const auto name_to_type_map_end = name_to_type_map.end(); std::vector results; results.reserve(names.size()); - for (auto& name : names) { + for (const std::string& name : names) { const TypeProto* type = nullptr; auto name_to_type_iter = name_to_type_map.find(name); @@ -4076,27 +4105,51 @@ ONNX_NAMESPACE::GraphProto Graph::ToGraphProto() const { // This is used for constructing full path for external data // if it exists + auto add_initializer = [](TensorList& output_initializers, const TensorProto& initializer) -> void { + TensorProto& output = *output_initializers.Add(); + output = initializer; + + // copy any in-memory external data into raw data + if (utils::HasExternalData(initializer)) { + const std::filesystem::path ignored; + std::basic_string location; + onnxruntime::FileOffsetType file_offset; + SafeInt tensor_byte_size; + + ORT_THROW_IF_ERROR(utils::GetExternalDataInfo(initializer, ignored, location, file_offset, tensor_byte_size)); + + if (location == onnxruntime::utils::kTensorProtoMemoryAddressTag) { + // file_offset is address + void* data = reinterpret_cast(file_offset); + + // set in raw data + output.clear_data_location(); + output.set_raw_data(data, tensor_byte_size); + } + } + }; + + auto* mutable_initializers = result.mutable_initializer(); + #if !defined(DISABLE_SPARSE_TENSORS) const auto& model_path = ModelPath(); // We want to make sure that sparse initializers do not appear // as dense duplicates within the initializers list. - if (!sparse_tensor_names_.empty()) { - const auto sparse_end = sparse_tensor_names_.end(); - auto* mutable_initializer = result.mutable_initializer(); - for (const auto& initializer : graph_proto_->initializer()) { - if (sparse_end == sparse_tensor_names_.find(initializer.name())) { - *mutable_initializer->Add() = initializer; - } else { - auto& sparse_initializer = *result.add_sparse_initializer(); - auto status = utils::DenseTensorToSparseTensorProto(initializer, model_path, sparse_initializer); - ORT_ENFORCE(status.IsOK(), "Failed to convert dense initializer to sparse"); - } + const bool has_sparse_initializers = !sparse_tensor_names_.empty(); + const auto sparse_end = sparse_tensor_names_.end(); + for (const auto& initializer : graph_proto_->initializer()) { + if (!has_sparse_initializers || sparse_end == sparse_tensor_names_.find(initializer.name())) { + add_initializer(*mutable_initializers, initializer); + } else { + auto& sparse_initializer = *result.add_sparse_initializer(); + auto status = utils::DenseTensorToSparseTensorProto(initializer, model_path, sparse_initializer); + ORT_ENFORCE(status.IsOK(), "Failed to convert dense initializer to sparse"); } - } else { - *result.mutable_initializer() = graph_proto_->initializer(); } #else - *result.mutable_initializer() = graph_proto_->initializer(); + for (const auto& initializer : graph_proto_->initializer()) { + add_initializer(*mutable_initializers, initializer); + } #endif return result; @@ -5345,6 +5398,9 @@ Status Graph::InlineFunction(Node& callnode) { } void Graph::SetInputs(gsl::span inputs) { + graph_inputs_including_initializers_.clear(); + graph_inputs_excluding_initializers_.clear(); + // creating graph from scratch // rely on SetGraphInputsOutputs() to fix up graph_inputs_excluding_initializers_ // if is_loaded_from_model_file_ == false @@ -5353,7 +5409,6 @@ void Graph::SetInputs(gsl::span inputs) { if (is_loaded_from_model_file_) { // graph loaded from model file - graph_inputs_excluding_initializers_.clear(); for (const auto* input : inputs) { ORT_ENFORCE(input->Exists(), "Input to set must exist."); if (name_to_initial_tensor_.find(input->Name()) == name_to_initial_tensor_.end()) { @@ -5370,6 +5425,7 @@ void Graph::SetInputs(gsl::span inputs) { } void Graph::SetOutputs(gsl::span outputs) { + graph_outputs_.clear(); graph_outputs_.reserve(outputs.size()); graph_outputs_.assign(outputs.begin(), outputs.end()); @@ -5688,4 +5744,207 @@ common::Status Graph::LoadFromOrtFormat(const onnxruntime::fbs::Graph& fbs_graph return Status::OK(); } +#if !defined(ORT_MINIMAL_BUILD) +namespace { +ValueInfoProto OrtValueInfoToOnnx(const OrtValueInfo& vi) { + // the model builder API checks that the OrtValueInfo has a complete and valid OrtTypeInfo instance and that the + // name is not null/empty. + ORT_ENFORCE(vi.type_info->type == ONNX_TYPE_TENSOR, + "Internal error. Model Editor API should only allow OrtValueInfo for tensor to be created."); + + ValueInfoProto value_info_proto; + value_info_proto.set_name(vi.name); + + auto* tensor = value_info_proto.mutable_type()->mutable_tensor_type(); + const OrtTensorTypeAndShapeInfo& tensor_info = *vi.type_info->tensor_type_info.get(); + tensor->set_elem_type(tensor_info.type); + + auto& shape = *tensor->mutable_shape(); + + size_t idx = 0; + for (auto dim : tensor_info.shape.GetDims()) { + auto& dim_proto = *shape.add_dim(); + if (dim >= 0) { + dim_proto.set_dim_value(dim); + } else { + const std::string& dim_param = tensor_info.dim_params[idx]; + // if empty leave the new dim_proto with neither dim_value nor dim_param set. this represents an 'unknown' dim + if (!dim_param.empty()) { + dim_proto.set_dim_param(dim_param); + } + } + } + + return value_info_proto; +} +} // namespace + +Status Graph::LoadFromModelEditorApiModel(const OrtGraph& api_graph, bool updating_existing_graph) { + ArgNameToTypeMap name_to_type_map; + + // NOTE: need to create NodeArgs as we go along + + // add inputs first. the shape from an input for a non-const initializer is preferred, so we want to create the + // NodeArg for the value using that + + auto add_graph_inputs_outputs = [&, this]( + const InlinedVector>& graph_inputs_or_outputs, + bool is_input) { + // when updating a model we don't require the inputs or outputs to be set if they're unchanged. + if (updating_existing_graph && graph_inputs_or_outputs.empty()) { + return; + } + + std::vector node_args; + node_args.reserve(graph_inputs_or_outputs.size()); + for (auto& ort_value_info : graph_inputs_or_outputs) { + ValueInfoProto value_info = OrtValueInfoToOnnx(*ort_value_info); + + name_to_type_map[value_info.name()] = value_info.type(); + node_args.push_back(&GetOrCreateNodeArg(value_info.name(), &value_info.type())); + } + + if (is_input) { + SetInputs(node_args); + } else { + SetOutputs(node_args); + } + }; + + auto add_initializers = [this](const std::unordered_map>& initializers, + bool is_external) { + for (auto& name_and_ortvalue : initializers) { + // convert from OrtValue to TensorProto + const std::string& name = name_and_ortvalue.first; + OrtValue& v = *name_and_ortvalue.second; + + ORT_ENFORCE(v.IsTensor(), "Initializers must be Tensors"); + const Tensor& t = v.Get(); + TensorProto& tensor_proto = *graph_proto_->add_initializer(); + + tensor_proto.set_name(name); + tensor_proto.set_data_type(t.GetElementType()); + for (auto dim : t.Shape().GetDims()) { + tensor_proto.add_dims(dim); + } + + if (is_external) { + // pre-existing memory that we don't own. avoid a copy by storing the pointer in the ExternalDataInfo + const void* data_offset = t.DataRaw(); // address of memory not offset into file + auto offset = narrow(reinterpret_cast(data_offset)); + + ExternalDataInfo::SetExternalLocationToProto(onnxruntime::utils::kTensorProtoMemoryAddressTag, + offset, t.SizeInBytes(), tensor_proto); + + // add OrtValue to ortvalue_initializers_ to keep it alive and to store the deleter if provided. + ortvalue_initializers_.emplace(name, std::move(v)); + } else { + tensor_proto.set_raw_data(t.DataRaw(), t.SizeInBytes()); + } + + TypeProto type_proto{TypeProtoFromTensorProto(tensor_proto)}; + ORT_IGNORE_RETURN_VALUE(GetOrCreateNodeArg(name, &type_proto)); + + name_to_initial_tensor_.emplace(name, &tensor_proto); + } + }; + + // process graph inputs first as we want the type/shape from them to be preferred if a graph input + // has a matching initializer + add_graph_inputs_outputs(api_graph.inputs, /*input*/ true); + + // add initializers + ortvalue_initializers_.reserve(api_graph.external_initializers.size()); + add_initializers(api_graph.external_initializers, /*is_external*/ true); + add_initializers(api_graph.initializers, /*is_external*/ false); + + // add graph outputs + add_graph_inputs_outputs(api_graph.outputs, /*input*/ false); + + // add nodes + for (const auto& ort_node : api_graph.nodes) { + const OrtNode& node = *ort_node; + + // convert Constant nodes to initializers + if (node.operator_name == "Constant" && node.domain_name == kOnnxDomain) { + // graph_proto_ provides storage + TensorProto& tensor = *graph_proto_->add_initializer(); + + // create NodeProto from OrtNode so we can use the existing conversion functions + NodeProto node_proto; + + // 'Constant' node has no inputs or attributes + ORT_RETURN_IF_NOT(node.input_names.empty() && node.attributes.size() == 1 && node.output_names.size() == 1, + node.node_name, + " is an invalid 'Constant' node. " + "Must have no inputs, one attribute and one output. "); + + node_proto.add_attribute()->CopyFrom(node.attributes[0]); + node_proto.add_output(node.output_names[0]); + + node_proto.set_op_type(node.operator_name); + node_proto.set_name(node.node_name); + node_proto.set_domain(node.domain_name); + + ORT_RETURN_IF_ERROR(utils::ConstantNodeProtoToTensorProto(node_proto, /*model_path*/ "", tensor)); + name_to_initial_tensor_.emplace(node.output_names[0], &tensor); + + continue; + } + + auto input_defs = CreateNodeArgs(node.input_names, name_to_type_map); + auto output_defs = CreateNodeArgs(node.output_names, name_to_type_map); + + const auto num_attributes = node.attributes.size(); + + NodeAttributes attributes; + attributes.reserve(num_attributes); + + for (const auto& attr : node.attributes) { + attributes[attr.name()] = attr; + } + + ORT_IGNORE_RETURN_VALUE(AddNode(node.node_name, node.operator_name, /*doc_string*/ "", + input_defs, output_defs, &attributes, node.domain_name)); + } + + return Resolve(); +} + +// static +Status Graph::LoadFromModelEditorApiModel(const OrtGraph& api_graph, + const Model& owning_model, + const std::unordered_map& domain_to_version, + IOnnxRuntimeOpSchemaCollectionPtr schema_registry, + bool strict_shape_type_inference, + const logging::Logger& logger, + std::unique_ptr& graph) { + graph = std::make_unique(owning_model, + domain_to_version, + schema_registry, + /*parent_graph*/ nullptr, /*parent_node*/ nullptr, + logger, + strict_shape_type_inference); + + return graph->LoadFromModelEditorApiModel(api_graph); +} + +Status Graph::UpdateUsingModelEditorApiModel(const OrtModel& api_model) { + for (auto& entry : api_model.domain_to_version) { + if (auto it = domain_to_version_.find(entry.first); it != domain_to_version_.end()) { + if (it->second != entry.second) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Domain version can not be changed for '", entry.first, + "'. Current version: ", it->second); + } + } else { + domain_to_version_.insert(entry); + } + } + + // this will replace inputs/outputs and add nodes. + return LoadFromModelEditorApiModel(*api_model.graph, /*updating_existing_graph*/ true); +} + +#endif // !defined(ORT_MINIMAL_BUILD) } // namespace onnxruntime diff --git a/onnxruntime/core/graph/graph_flatbuffers_utils.cc b/onnxruntime/core/graph/graph_flatbuffers_utils.cc index 922759b02e75f..199aa79cc1dde 100644 --- a/onnxruntime/core/graph/graph_flatbuffers_utils.cc +++ b/onnxruntime/core/graph/graph_flatbuffers_utils.cc @@ -300,8 +300,6 @@ Status LoadInitializerOrtFormat(const fbs::Tensor& fbs_tensor, TensorProto& init const auto* fbs_raw_data = fbs_tensor.raw_data(); if (fbs_raw_data) { if (load_options.can_use_flatbuffer_for_initializers && fbs_raw_data->size() > 127) { - initializer.set_data_location(ONNX_NAMESPACE::TensorProto_DataLocation_EXTERNAL); - static_assert(sizeof(void*) <= sizeof(ExternalDataInfo::OFFSET_TYPE)); const void* data_offset = fbs_raw_data->Data(); // we reinterpret_cast this back to void* in tensorprotoutils.cc:GetExtDataFromTensorProto. @@ -309,15 +307,9 @@ Status LoadInitializerOrtFormat(const fbs::Tensor& fbs_tensor, TensorProto& init // high bit, but that should be unlikely in a scenario where we care about memory usage enough to use this path. auto offset = narrow(reinterpret_cast(data_offset)); - ONNX_NAMESPACE::StringStringEntryProto* entry = initializer.mutable_external_data()->Add(); - entry->set_key("location"); - entry->set_value(ToUTF8String(onnxruntime::utils::kTensorProtoMemoryAddressTag)); - entry = initializer.mutable_external_data()->Add(); - entry->set_key("offset"); - entry->set_value(std::to_string(offset)); - entry = initializer.mutable_external_data()->Add(); - entry->set_key("length"); - entry->set_value(std::to_string(fbs_raw_data->size())); + ExternalDataInfo::SetExternalLocationToProto(onnxruntime::utils::kTensorProtoMemoryAddressTag, + offset, fbs_raw_data->size(), initializer); + } else { // fbs_raw_data is uint8_t vector, so the size is byte size initializer.set_raw_data(fbs_raw_data->Data(), fbs_raw_data->size()); diff --git a/onnxruntime/core/graph/model.cc b/onnxruntime/core/graph/model.cc index be0531e6473fb..436af7115eb1a 100644 --- a/onnxruntime/core/graph/model.cc +++ b/onnxruntime/core/graph/model.cc @@ -7,6 +7,7 @@ #include "core/flatbuffers/flatbuffers_utils.h" #include "core/framework/tensorprotoutils.h" #include "core/graph/model.h" +#include "core/graph/model_editor_api_types.h" #include "core/graph/model_load_utils.h" #ifdef _MSC_VER @@ -81,7 +82,7 @@ Model::Model(const std::string& graph_name, const std::vector& model_local_functions, const logging::Logger& logger, const ModelOptions& options) - : model_path_(model_path) { + : model_path_(model_path), check_load_cancellation_fn_(options.check_load_cancellation_fn) { model_proto_.set_ir_version(ONNX_NAMESPACE::Version::IR_VERSION); model_proto_.mutable_graph()->set_name(graph_name); model_metadata_ = model_metadata; @@ -160,7 +161,7 @@ Model::Model(const ModelProto& model_proto, const PathString& model_path, Model::Model(ModelProto&& model_proto, const PathString& model_path, const IOnnxRuntimeOpSchemaRegistryList* local_registries, const logging::Logger& logger, const ModelOptions& options) - : model_path_(model_path) { + : model_path_(model_path), check_load_cancellation_fn_(options.check_load_cancellation_fn) { if (!utils::HasGraph(model_proto)) { ORT_THROW("ModelProto does not have a graph."); } @@ -434,6 +435,11 @@ Status Model::Load(const ModelProto& model_proto, ORT_TRY { model = std::make_unique(model_proto, model_path, local_registries, logger, options); } + ORT_CATCH(const OnnxRuntimeException& ex) { + ORT_HANDLE_EXCEPTION([&]() { + status = Status(ex.Category(), ex.Code(), ex.what()); + }); + } ORT_CATCH(const std::exception& ex) { ORT_HANDLE_EXCEPTION([&]() { status = Status(ONNXRUNTIME, INVALID_ARGUMENT, "Failed to load model with error: " + std::string(ex.what())); @@ -473,6 +479,11 @@ Status Model::Load(ModelProto&& model_proto, ORT_TRY { model = std::make_unique(std::move(model_proto), model_path, local_registries, logger, options); } + ORT_CATCH(const OnnxRuntimeException& ex) { + ORT_HANDLE_EXCEPTION([&]() { + status = Status(ex.Category(), ex.Code(), ex.what()); + }); + } ORT_CATCH(const std::exception& ex) { ORT_HANDLE_EXCEPTION([&]() { status = Status(ONNXRUNTIME, INVALID_ARGUMENT, "Failed to load model with error: " + std::string(ex.what())); @@ -508,6 +519,11 @@ static Status LoadModelHelper(const T& file_path, Loader loader) { ORT_TRY { status = loader(fd); } + ORT_CATCH(const OnnxRuntimeException& ex) { + ORT_HANDLE_EXCEPTION([&]() { + status = Status(ex.Category(), ex.Code(), ex.what()); + }); + } ORT_CATCH(const std::exception& ex) { ORT_HANDLE_EXCEPTION([&]() { status = Status(ONNXRUNTIME, FAIL, ex.what()); @@ -738,6 +754,36 @@ Status Model::Load(int fd, const PathString& model_path, std::shared_ptr& return Status::OK(); } +// static +common::Status Model::LoadFromModelEditorApiModel(const OrtModel& model_editor_api_model, + const IOnnxRuntimeOpSchemaRegistryList* local_registries, + const ModelOptions& options, + const logging::Logger& logger, + std::unique_ptr& model) { + model = std::make_unique(); + model->model_proto_.set_ir_version(ONNX_NAMESPACE::Version::IR_VERSION); + // The optimizer Initializer class requires a path if external data is used, however in the Graph API usage the + // external data is pointing to pre-allocated memory and does not require a path. Set a dummy value to make it happy. + model->model_path_ = std::filesystem::path("_GRAPH_API_MODEL_"); + + auto schema_registry = std::make_shared(); + if (local_registries != nullptr) { + for (const auto& schema_collection : *local_registries) { + schema_registry->RegisterRegistry(schema_collection); + } + } + + ORT_RETURN_IF_ERROR(Graph::LoadFromModelEditorApiModel(*model_editor_api_model.graph, + *model, + model_editor_api_model.domain_to_version, + schema_registry, + options.strict_shape_type_inference, + logger, + model->graph_)); + + return Status::OK(); +} + Status Model::Save(Model& model, int p_fd) { if (p_fd < 0) { return Status(ONNXRUNTIME, INVALID_ARGUMENT, " is less than 0."); @@ -917,5 +963,4 @@ common::Status Model::LoadFromOrtFormat(const fbs::Model& fbs_model, #endif return Status::OK(); } - } // namespace onnxruntime diff --git a/onnxruntime/core/graph/model.h b/onnxruntime/core/graph/model.h index 2d2086aef41fd..70f82bcfb160b 100644 --- a/onnxruntime/core/graph/model.h +++ b/onnxruntime/core/graph/model.h @@ -11,6 +11,7 @@ #include "core/common/flatbuffers.h" +#include "core/framework/session_options.h" #include "core/graph/graph_viewer.h" #include "core/graph/ort_format_load_options.h" #include "core/session/onnxruntime_c_api.h" @@ -38,6 +39,14 @@ struct ModelOptions { // be returned. bool strict_shape_type_inference; + CheckLoadCancellationFn check_load_cancellation_fn; + + ModelOptions(bool allow_released_opsets_only, bool strict_shape_type_inference, + CheckLoadCancellationFn check_load_cancellation_fn) + : allow_released_opsets_only(allow_released_opsets_only), + strict_shape_type_inference(strict_shape_type_inference), + check_load_cancellation_fn(std::move(check_load_cancellation_fn)) {} + ModelOptions(bool allow_released_opsets_only, bool strict_shape_type_inference) : allow_released_opsets_only(allow_released_opsets_only), strict_shape_type_inference(strict_shape_type_inference) {} @@ -102,6 +111,11 @@ class Model { #endif // !defined(ORT_MINIMAL_BUILD) + // Check for load cancellation. + bool IsLoadCancellationFlagSet() const noexcept { + return check_load_cancellation_fn_ && check_load_cancellation_fn_(); + } + #if !defined(ORT_MINIMAL_BUILD) // Get model's IR version. // Return if not specified. @@ -280,6 +294,12 @@ class Model { const logging::Logger& logger, const ModelOptions& options = {}); + static common::Status LoadFromModelEditorApiModel(const OrtModel& graph_api_model, + const IOnnxRuntimeOpSchemaRegistryList* local_registries, + const ModelOptions& options, + const logging::Logger& logger, + std::unique_ptr& model); + common::Status SaveToOrtFormat(flatbuffers::FlatBufferBuilder& builder, flatbuffers::Offset& model) const; @@ -333,9 +353,11 @@ class Model { ModelMetaData model_metadata_; // Path to model file. May be empty. - const std::filesystem::path model_path_; + std::filesystem::path model_path_; // Main graph of the model. std::unique_ptr graph_; + + CheckLoadCancellationFn check_load_cancellation_fn_; }; } // namespace onnxruntime diff --git a/onnxruntime/core/graph/model_editor_api_types.h b/onnxruntime/core/graph/model_editor_api_types.h new file mode 100644 index 0000000000000..d72bd13093b61 --- /dev/null +++ b/onnxruntime/core/graph/model_editor_api_types.h @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/common/inlined_containers_fwd.h" +#include "core/framework/ort_value.h" +#include "core/framework/onnxruntime_typeinfo.h" +#include "core/graph/onnx_protobuf.h" + +// ORT C interface types for OrtGraphApi can't be in a namespace. +// We need to define them here so onnxruntime::Model can be created from OrtModel. + +struct OrtValueInfo { + std::string name; + std::unique_ptr type_info; +}; + +struct OrtOpAttr { + ONNX_NAMESPACE::AttributeProto attr_proto; +}; + +struct OrtNode { + std::string operator_name; + std::string domain_name; + std::string node_name; + + // OrtOpAttr is 1:1 with ONNX_NAMESPACE::AttributeProto currently. + // https://github.com/microsoft/onnxruntime/blob/bd5a759d0cdbed6e7f611c990d4eb5457a9ecf60/onnxruntime/core/session/standalone_op_invoker.cc#L318 + onnxruntime::InlinedVector attributes; + onnxruntime::InlinedVector input_names; + onnxruntime::InlinedVector output_names; + + // FUTURE if we need control flow nodes + // std::unordered_map subgraphs; +}; + +struct OrtGraph { + onnxruntime::InlinedVector> inputs; + onnxruntime::InlinedVector> outputs; + std::unordered_map> initializers; + std::unordered_map> external_initializers; + std::vector> nodes; +}; + +struct OrtModel { + std::unique_ptr graph; + std::unordered_map domain_to_version; +}; diff --git a/onnxruntime/core/mlas/inc/mlas.h b/onnxruntime/core/mlas/inc/mlas.h index 1401e27ca77e5..db21157d2fdce 100644 --- a/onnxruntime/core/mlas/inc/mlas.h +++ b/onnxruntime/core/mlas/inc/mlas.h @@ -63,7 +63,10 @@ Module Name: #endif #if defined(__wasm__) #define MLAS_TARGET_WASM -#if defined(__wasm_simd128__) +#if defined(__wasm_relaxed_simd__) +#define MLAS_TARGET_WASM_RELAXED_SIMD +#define MLAS_TARGET_WASM_SIMD +#elif defined(__wasm_simd128__) #define MLAS_TARGET_WASM_SIMD #else #define MLAS_TARGET_WASM_SCALAR @@ -1030,6 +1033,16 @@ MlasComputeSoftcap( T cap ); +template +void +MLASCALL +MlasEltwiseAdd( + const T* left, + const T* right, + T* output, + size_t N + ); + template void MLASCALL diff --git a/onnxruntime/core/mlas/inc/mlas_qnbit.h b/onnxruntime/core/mlas/inc/mlas_qnbit.h index 9608644a22523..3627989609737 100644 --- a/onnxruntime/core/mlas/inc/mlas_qnbit.h +++ b/onnxruntime/core/mlas/inc/mlas_qnbit.h @@ -123,6 +123,7 @@ MlasIsQNBitGemmAvailable( * @param[in] BatchN number of batches * @param[in] BlkBitWidth quantized value bit width (e.g., 4 means 4 bit ints) * @param[in] BlkLen number of quantized values per block + * @param[in] HasZeroPoint whether zero points are provided * @param[in] ComputeType GEMM compute type (e.g., multiplying float or int8 values) */ size_t MLASCALL @@ -133,6 +134,7 @@ MlasQNBitGemmBatchWorkspaceSize( size_t BatchN, size_t BlkBitWidth, size_t BlkLen, + bool HasZeroPoint, MLAS_QNBIT_GEMM_COMPUTE_TYPE ComputeType ); @@ -147,6 +149,7 @@ MlasQNBitGemmBatchWorkspaceSize( * @param[in] K column size of matrix A and row size of matrix B * @param[in] BlkBitWidth quantized value bit width (e.g., 4 means 4 bit ints) * @param[in] BlkLen number of quantized values per block + * @param[in] HasZeroPoint whether zero points are provided * @param[in] ComputeType GEMM compute type (e.g., multiplying float or int8 values) */ size_t MLASCALL @@ -155,6 +158,7 @@ MlasQNBitGemmPackQuantBDataSize( size_t K, size_t BlkBitWidth, size_t BlkLen, + bool HasZeroPoint, MLAS_QNBIT_GEMM_COMPUTE_TYPE ComputeType ); @@ -181,7 +185,7 @@ MlasQNBitGemmPackQuantBDataSize( * @param[in] QuantBData quantized B data * @param[in] PackedQuantBDataAndOrBlkSum buffer to store packed quantized B data and/or BlkSum * @param[in] QuantBScale quantized B scale - * @param[in] has_zp_input whether QuantBZeroPoint is provided + * @param[in] HasZeroPoint whether QuantBZeroPoint is provided * @param[in] QuantBZeroPoint quantized B zero point * @param[in] ThreadPool thread pool to use (no parallel if nullptr) */ @@ -195,7 +199,25 @@ MlasQNBitGemmPackQuantBData( const void* QuantBData, void* PackedQuantBDataAndOrBlkSum, const void* QuantBScale, - bool has_zp_input, + bool HasZeroPoint, const void* QuantBZeroPoint, MLAS_THREADPOOL* ThreadPool ); + +/** + * @brief Returns true if scales are packed when calling MlasQNBitGemmPackQuantBData the first time. + * + * @param[in] K column size of matrix A and row size of matrix B + * @param[in] BlkBitWidth quantized value bit width (e.g., 4 means 4 bit ints) + * @param[in] BlkLen number of quantized values per block + * @param[in] ComputeType GEMM compute type (e.g., multiplying float or int8 values) + * @param[in] HasZeroPoint whether QuantBZeroPoint is provided + */ +bool MLASCALL +MlasQNBitGemmScalesPacked( + size_t K, + size_t BlkBitWidth, + size_t BlkLen, + MLAS_QNBIT_GEMM_COMPUTE_TYPE ComputeType, + bool HasZeroPoint +); diff --git a/onnxruntime/core/mlas/lib/eltwise.cpp b/onnxruntime/core/mlas/lib/eltwise.cpp new file mode 100644 index 0000000000000..f63d71b40bfbb --- /dev/null +++ b/onnxruntime/core/mlas/lib/eltwise.cpp @@ -0,0 +1,71 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the MIT License. + +Module Name: + + eltwise.cpp + +Abstract: + + This module implements routines to compute element-wise operations on two vectors. + + Currently supported element-wise operations: + - Add + +--*/ + +#include "mlasi.h" +#include "eltwise.h" + +template <> +void +MLASCALL +MlasEltwiseAdd( + const float* left, + const float* right, + float* output, + size_t N +) { + while (N > 0) { + if (N >= 4) { + MLAS_FLOAT32X4 LeftVec = MlasLoadFloat32x4(left); + MLAS_FLOAT32X4 RightVec = MlasLoadFloat32x4(right); + + MLAS_FLOAT32X4 ResultVec = MlasAddFloat32x4(LeftVec, RightVec); + + MlasStoreFloat32x4(output, ResultVec); + + left += 4; + right += 4; + output += 4; + N -= 4; + } else { + *output = *left + *right; + + left += 1; + right += 1; + output += 1; + N -= 1; + } + } +} + + +template <> +void +MLASCALL +MlasEltwiseAdd( + const MLAS_FP16* left, + const MLAS_FP16* right, + MLAS_FP16* output, + size_t N +) { + const auto* dispatch = GetMlasPlatform().EltwiseDispatch; + if (dispatch == nullptr || dispatch->Add_Fp16 == nullptr) { + MLAS_THROW_EX(std::runtime_error, "Add_Fp16 is not supported."); + } + dispatch->Add_Fp16(left, right, output, N); +} diff --git a/onnxruntime/core/mlas/lib/eltwise.h b/onnxruntime/core/mlas/lib/eltwise.h new file mode 100644 index 0000000000000..a8345c499f6b7 --- /dev/null +++ b/onnxruntime/core/mlas/lib/eltwise.h @@ -0,0 +1,37 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the MIT License. + +Module Name: + + eltwise.h + +Abstract: + + This module includes kernel function prototypes and helper functions for + element-wise operations. + +--*/ +#pragma once + +#include "mlasi.h" + +struct MLAS_ELTWISE_DISPATCH { + /** + * @brief Compute the element-wise addition of the two given vectors + * @param left Address of the left operand + * @param right Address of the right operand + * @param output Address of the output array. Could be the same as the input array. + * @param N Number of elements in the input arrays + */ + typedef void(Add_Fp16_Fn)( + const MLAS_FP16* left, + const MLAS_FP16* right, + MLAS_FP16* output, + size_t N + ); + + Add_Fp16_Fn* Add_Fp16 = nullptr; +}; diff --git a/onnxruntime/core/mlas/lib/eltwise_kernel_neon.cpp b/onnxruntime/core/mlas/lib/eltwise_kernel_neon.cpp new file mode 100644 index 0000000000000..415c1281c808e --- /dev/null +++ b/onnxruntime/core/mlas/lib/eltwise_kernel_neon.cpp @@ -0,0 +1,32 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the MIT License. + +Module Name: + + eltwise_kernel_neon.cpp + +Abstract: + + This module implements the element-wise kernels for ARM NEON. + +--*/ + +#include "eltwise.h" +#include "eltwise_kernel_neon.h" + +// +// Kernel dispatch structure definition. +// +const MLAS_ELTWISE_DISPATCH MlasEltwiseDispatchNeon = []() { + MLAS_ELTWISE_DISPATCH d; + +#if defined(MLAS_F16VEC_INTRINSICS_SUPPORTED) && defined(MLAS_TARGET_ARM64) + if (MlasFp16AccelerationSupported()) { + d.Add_Fp16 = eltwise_neon::Add_Kernel_Fp16; + } +#endif + return d; +}(); diff --git a/onnxruntime/core/mlas/lib/eltwise_kernel_neon.h b/onnxruntime/core/mlas/lib/eltwise_kernel_neon.h new file mode 100644 index 0000000000000..d99a3e97c21f2 --- /dev/null +++ b/onnxruntime/core/mlas/lib/eltwise_kernel_neon.h @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the MIT License. + +Module Name: + + eltwise_kernel_neon.h + +Abstract: + + This module includes function declarations and common helper functions for + element-wise operations on ARM cpu. + +--*/ + +#pragma once + +#include + +#include "mlasi.h" + +namespace eltwise_neon { + +void Add_Kernel_Fp16(const MLAS_FP16* left, const MLAS_FP16* right, MLAS_FP16* output, size_t N); + +} // namespace eltwise_neon diff --git a/onnxruntime/core/mlas/lib/eltwise_kernel_neon_fp16.cpp b/onnxruntime/core/mlas/lib/eltwise_kernel_neon_fp16.cpp new file mode 100644 index 0000000000000..decbdb576d5cd --- /dev/null +++ b/onnxruntime/core/mlas/lib/eltwise_kernel_neon_fp16.cpp @@ -0,0 +1,118 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the MIT License. + +Module Name: + + eltwise_kernel_neon_fp16.cpp + +Abstract: + + This module implements the fp16 element-wise kernels for ARM NEON. + +--*/ +#include +#include + +#include "fp16_common.h" +#include "eltwise.h" +#include "eltwise_kernel_neon.h" + +namespace eltwise_neon { + +void Add_Kernel_Fp16(const MLAS_FP16* left, const MLAS_FP16* right, MLAS_FP16* output, size_t N) { + const auto* left_fp16 = reinterpret_cast(left); + const auto* right_fp16 = reinterpret_cast(right); + auto* output_fp16 = reinterpret_cast<_mlas_fp16_*>(output); + + while (N >= 32) { + auto l0 = MlasLoadFloat16x8(left_fp16); + auto l1 = MlasLoadFloat16x8(left_fp16 + 8); + auto l2 = MlasLoadFloat16x8(left_fp16 + 16); + auto l3 = MlasLoadFloat16x8(left_fp16 + 24); + + auto r0 = MlasLoadFloat16x8(right_fp16); + auto r1 = MlasLoadFloat16x8(right_fp16 + 8); + auto r2 = MlasLoadFloat16x8(right_fp16 + 16); + auto r3 = MlasLoadFloat16x8(right_fp16 + 24); + + auto o0 = MlasAddFloat16(l0, r0); + auto o1 = MlasAddFloat16(l1, r1); + auto o2 = MlasAddFloat16(l2, r2); + auto o3 = MlasAddFloat16(l3, r3); + + MlasStoreFloat16x8(output_fp16, o0); + MlasStoreFloat16x8(output_fp16 + 8, o1); + MlasStoreFloat16x8(output_fp16 + 16, o2); + MlasStoreFloat16x8(output_fp16 + 24, o3); + + left_fp16 += 32; + right_fp16 += 32; + output_fp16 += 32; + N -= 32; + } + + if (N & 16) { + auto l0 = MlasLoadFloat16x8(left_fp16); + auto l1 = MlasLoadFloat16x8(left_fp16 + 8); + + auto r0 = MlasLoadFloat16x8(right_fp16); + auto r1 = MlasLoadFloat16x8(right_fp16 + 8); + + auto o0 = MlasAddFloat16(l0, r0); + auto o1 = MlasAddFloat16(l1, r1); + + MlasStoreFloat16x8(output_fp16, o0); + MlasStoreFloat16x8(output_fp16 + 8, o1); + + left_fp16 += 16; + right_fp16 += 16; + output_fp16 += 16; + N -= 16; + } + + if (N & 8) { + auto l0 = MlasLoadFloat16x8(left_fp16); + auto r0 = MlasLoadFloat16x8(right_fp16); + auto o0 = MlasAddFloat16(l0, r0); + MlasStoreFloat16x8(output_fp16, o0); + + left_fp16 += 8; + right_fp16 += 8; + output_fp16 += 8; + N -= 8; + } + + if (N & 4) { + auto l0 = MlasLoadFloat16x4(left_fp16); + auto r0 = MlasLoadFloat16x4(right_fp16); + auto o0 = MlasAddFloat16(l0, r0); + MlasStoreFloat16x4(output_fp16, o0); + + left_fp16 += 4; + right_fp16 += 4; + output_fp16 += 4; + N -= 4; + } + + if (N == 3) { + auto l0 = MlasLoadPartialFloat16x4(left_fp16, 3); + auto r0 = MlasLoadPartialFloat16x4(right_fp16, 3); + auto o0 = MlasAddFloat16(l0, r0); + MlasStorePartialFloat16x4(output_fp16, o0, 3); + } else if (N == 2) { + auto l0 = MlasLoadPartialFloat16x4(left_fp16, 2); + auto r0 = MlasLoadPartialFloat16x4(right_fp16, 2); + auto o0 = MlasAddFloat16(l0, r0); + MlasStorePartialFloat16x4(output_fp16, o0, 2); + } else if (N == 1) { + auto l0 = MlasLoadPartialFloat16x4(left_fp16, 1); + auto r0 = MlasLoadPartialFloat16x4(right_fp16, 1); + auto o0 = MlasAddFloat16(l0, r0); + MlasStorePartialFloat16x4(output_fp16, o0, 1); + } +} + +} // namespace eltwise_neon diff --git a/onnxruntime/core/mlas/lib/halfgemm.cpp b/onnxruntime/core/mlas/lib/halfgemm.cpp index 879eca8097176..66a335665d024 100644 --- a/onnxruntime/core/mlas/lib/halfgemm.cpp +++ b/onnxruntime/core/mlas/lib/halfgemm.cpp @@ -522,15 +522,9 @@ MlasGemmBatch( } const double Complexity = double(M) * double(N) * double(K) * double(BatchSize); - ptrdiff_t TargetThreadCount; - - if (Complexity < double(MLAS_HGEMM_THREAD_COMPLEXITY) * GetMlasPlatform().MaximumThreadCount) { - TargetThreadCount = ptrdiff_t(Complexity / double(MLAS_HGEMM_THREAD_COMPLEXITY)) + 1; - } else { - TargetThreadCount = GetMlasPlatform().MaximumThreadCount; - } - + ptrdiff_t TargetThreadCount = ptrdiff_t(Complexity / double(MLAS_HGEMM_THREAD_COMPLEXITY)) + 1; ptrdiff_t MaximumThreadCount = MlasGetMaximumThreadCount(ThreadPool); + if (TargetThreadCount >= MaximumThreadCount) { TargetThreadCount = MaximumThreadCount; } diff --git a/onnxruntime/core/mlas/lib/kai_ukernel_interface.cpp b/onnxruntime/core/mlas/lib/kai_ukernel_interface.cpp new file mode 100644 index 0000000000000..fdada83cc6582 --- /dev/null +++ b/onnxruntime/core/mlas/lib/kai_ukernel_interface.cpp @@ -0,0 +1,81 @@ +// +// SPDX-FileCopyrightText: Copyright 2025 Arm Limited and/or its affiliates +// +// SPDX-License-Identifier: MIT +// + +#include "kai_ukernel_interface.h" +#include "mlasi.h" + +#include "kai/ukernels/matmul/matmul_clamp_f32_qai8dxp_qsi4c32p/kai_matmul_clamp_f32_qai8dxp1x4_qsi4c32p4x4_1x4_neon_dotprod.h" +#include "kai/ukernels/matmul/matmul_clamp_f32_qai8dxp_qsi4c32p/kai_matmul_clamp_f32_qai8dxp4x4_qsi4c32p4x4_16x4_neon_dotprod.h" +#include "kai/ukernels/matmul/matmul_clamp_f32_qai8dxp_qsi4c32p/kai_matmul_clamp_f32_qai8dxp1x8_qsi4c32p4x8_1x4x32_neon_dotprod.h" +#include "kai/ukernels/matmul/matmul_clamp_f32_qai8dxp_qsi4c32p/kai_matmul_clamp_f32_qai8dxp4x8_qsi4c32p4x8_16x4x32_neon_i8mm.h" + +const kai_matmul_clamp_f32_qai8dxp_qsi4c32p_ukernel kai_matmul_clamp_f32_qai8dxp1x4_qsi4c32p4x4_1x4_neon_dotprod = + {kai_get_m_step_matmul_clamp_f32_qai8dxp1x4_qsi4c32p4x4_1x4_neon_dotprod, + kai_get_n_step_matmul_clamp_f32_qai8dxp1x4_qsi4c32p4x4_1x4_neon_dotprod, + kai_get_mr_matmul_clamp_f32_qai8dxp1x4_qsi4c32p4x4_1x4_neon_dotprod, + kai_get_nr_matmul_clamp_f32_qai8dxp1x4_qsi4c32p4x4_1x4_neon_dotprod, + kai_get_kr_matmul_clamp_f32_qai8dxp1x4_qsi4c32p4x4_1x4_neon_dotprod, + kai_get_sr_matmul_clamp_f32_qai8dxp1x4_qsi4c32p4x4_1x4_neon_dotprod, + kai_get_lhs_packed_offset_matmul_clamp_f32_qai8dxp1x4_qsi4c32p4x4_1x4_neon_dotprod, + kai_get_rhs_packed_offset_matmul_clamp_f32_qai8dxp1x4_qsi4c32p4x4_1x4_neon_dotprod, + kai_get_dst_offset_matmul_clamp_f32_qai8dxp1x4_qsi4c32p4x4_1x4_neon_dotprod, + kai_get_dst_size_matmul_clamp_f32_qai8dxp1x4_qsi4c32p4x4_1x4_neon_dotprod, + kai_run_matmul_clamp_f32_qai8dxp1x4_qsi4c32p4x4_1x4_neon_dotprod}; + +const kai_matmul_clamp_f32_qai8dxp_qsi4c32p_ukernel kai_matmul_clamp_f32_qai8dxp4x4_qsi4c32p4x4_16x4_neon_dotprod = + {kai_get_m_step_matmul_clamp_f32_qai8dxp4x4_qsi4c32p4x4_16x4_neon_dotprod, + kai_get_n_step_matmul_clamp_f32_qai8dxp4x4_qsi4c32p4x4_16x4_neon_dotprod, + kai_get_mr_matmul_clamp_f32_qai8dxp4x4_qsi4c32p4x4_16x4_neon_dotprod, + kai_get_nr_matmul_clamp_f32_qai8dxp4x4_qsi4c32p4x4_16x4_neon_dotprod, + kai_get_kr_matmul_clamp_f32_qai8dxp4x4_qsi4c32p4x4_16x4_neon_dotprod, + kai_get_sr_matmul_clamp_f32_qai8dxp4x4_qsi4c32p4x4_16x4_neon_dotprod, + kai_get_lhs_packed_offset_matmul_clamp_f32_qai8dxp4x4_qsi4c32p4x4_16x4_neon_dotprod, + kai_get_rhs_packed_offset_matmul_clamp_f32_qai8dxp4x4_qsi4c32p4x4_16x4_neon_dotprod, + kai_get_dst_offset_matmul_clamp_f32_qai8dxp4x4_qsi4c32p4x4_16x4_neon_dotprod, + kai_get_dst_size_matmul_clamp_f32_qai8dxp4x4_qsi4c32p4x4_16x4_neon_dotprod, + kai_run_matmul_clamp_f32_qai8dxp4x4_qsi4c32p4x4_16x4_neon_dotprod}; + +const kai_matmul_clamp_f32_qai8dxp_qsi4c32p_ukernel kai_matmul_clamp_f32_qai8dxp1x8_qsi4c32p4x8_1x4x32_neon_dotprod = + {kai_get_m_step_matmul_clamp_f32_qai8dxp1x8_qsi4c32p4x8_1x4x32_neon_dotprod, + kai_get_n_step_matmul_clamp_f32_qai8dxp1x8_qsi4c32p4x8_1x4x32_neon_dotprod, + kai_get_mr_matmul_clamp_f32_qai8dxp1x8_qsi4c32p4x8_1x4x32_neon_dotprod, + kai_get_nr_matmul_clamp_f32_qai8dxp1x8_qsi4c32p4x8_1x4x32_neon_dotprod, + kai_get_kr_matmul_clamp_f32_qai8dxp1x8_qsi4c32p4x8_1x4x32_neon_dotprod, + kai_get_sr_matmul_clamp_f32_qai8dxp1x8_qsi4c32p4x8_1x4x32_neon_dotprod, + kai_get_lhs_packed_offset_matmul_clamp_f32_qai8dxp1x8_qsi4c32p4x8_1x4x32_neon_dotprod, + kai_get_rhs_packed_offset_matmul_clamp_f32_qai8dxp1x8_qsi4c32p4x8_1x4x32_neon_dotprod, + kai_get_dst_offset_matmul_clamp_f32_qai8dxp1x8_qsi4c32p4x8_1x4x32_neon_dotprod, + kai_get_dst_size_matmul_clamp_f32_qai8dxp1x8_qsi4c32p4x8_1x4x32_neon_dotprod, + kai_run_matmul_clamp_f32_qai8dxp1x8_qsi4c32p4x8_1x4x32_neon_dotprod}; + +const kai_matmul_clamp_f32_qai8dxp_qsi4c32p_ukernel kai_matmul_clamp_f32_qai8dxp4x8_qsi4c32p4x8_16x4x32_neon_i8mm = + {kai_get_m_step_matmul_clamp_f32_qai8dxp4x8_qsi4c32p4x8_16x4x32_neon_i8mm, + kai_get_n_step_matmul_clamp_f32_qai8dxp4x8_qsi4c32p4x8_16x4x32_neon_i8mm, + kai_get_mr_matmul_clamp_f32_qai8dxp4x8_qsi4c32p4x8_16x4x32_neon_i8mm, + kai_get_nr_matmul_clamp_f32_qai8dxp4x8_qsi4c32p4x8_16x4x32_neon_i8mm, + kai_get_kr_matmul_clamp_f32_qai8dxp4x8_qsi4c32p4x8_16x4x32_neon_i8mm, + kai_get_sr_matmul_clamp_f32_qai8dxp4x8_qsi4c32p4x8_16x4x32_neon_i8mm, + kai_get_lhs_packed_offset_matmul_clamp_f32_qai8dxp4x8_qsi4c32p4x8_16x4x32_neon_i8mm, + kai_get_rhs_packed_offset_matmul_clamp_f32_qai8dxp4x8_qsi4c32p4x8_16x4x32_neon_i8mm, + kai_get_dst_offset_matmul_clamp_f32_qai8dxp4x8_qsi4c32p4x8_16x4x32_neon_i8mm, + kai_get_dst_size_matmul_clamp_f32_qai8dxp4x8_qsi4c32p4x8_16x4x32_neon_i8mm, + kai_run_matmul_clamp_f32_qai8dxp4x8_qsi4c32p4x8_16x4x32_neon_i8mm}; + +const kai_matmul_clamp_f32_qai8dxp_qsi4c32p_ukernel& GetKleidiAIGemmUKernel() { + if (MLAS_CPUIDINFO::GetCPUIDInfo().HasArmNeon_I8MM()) { + return kai_matmul_clamp_f32_qai8dxp4x8_qsi4c32p4x8_16x4x32_neon_i8mm; + } else { + return kai_matmul_clamp_f32_qai8dxp4x4_qsi4c32p4x4_16x4_neon_dotprod; + } +} + +const kai_matmul_clamp_f32_qai8dxp_qsi4c32p_ukernel& GetKleidiAIGemvUKernel() { + if (MLAS_CPUIDINFO::GetCPUIDInfo().HasArmNeon_I8MM()) { + return kai_matmul_clamp_f32_qai8dxp1x8_qsi4c32p4x8_1x4x32_neon_dotprod; + } else { + return kai_matmul_clamp_f32_qai8dxp1x4_qsi4c32p4x4_1x4_neon_dotprod; + } +} diff --git a/onnxruntime/core/mlas/lib/kai_ukernel_interface.h b/onnxruntime/core/mlas/lib/kai_ukernel_interface.h new file mode 100644 index 0000000000000..1a6f111d1c794 --- /dev/null +++ b/onnxruntime/core/mlas/lib/kai_ukernel_interface.h @@ -0,0 +1,12 @@ +// +// SPDX-FileCopyrightText: Copyright 2025 Arm Limited and/or its affiliates +// +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include "kai/ukernels/matmul/matmul_clamp_f32_qai8dxp_qsi4c32p/kai_matmul_clamp_f32_qai8dxp_qsi4c32p_interface.h" + +const kai_matmul_clamp_f32_qai8dxp_qsi4c32p_ukernel& GetKleidiAIGemmUKernel(); +const kai_matmul_clamp_f32_qai8dxp_qsi4c32p_ukernel& GetKleidiAIGemvUKernel(); diff --git a/onnxruntime/core/mlas/lib/mlasi.h b/onnxruntime/core/mlas/lib/mlasi.h index 0681b49252495..4782e479753a2 100644 --- a/onnxruntime/core/mlas/lib/mlasi.h +++ b/onnxruntime/core/mlas/lib/mlasi.h @@ -996,9 +996,14 @@ extern const MLAS_GEMM_QUANT_DISPATCH MlasGemmS8S8DispatchSdot; extern const MLAS_GEMM_QUANT_DISPATCH MlasGemmU8X8DispatchUmmla; extern const MLAS_GEMM_QUANT_DISPATCH MlasGemmS8S8DispatchSmmla; extern const MLAS_GEMM_QUANT_DISPATCH MlasGemmU8X8DispatchWasmSimd; +extern const MLAS_GEMM_QUANT_DISPATCH MlasGemmU8X8DispatchWasmRelaxedSimd; extern const MLAS_GEMM_QUANT_DISPATCH MlasGemmQuantDispatchDefault; extern const MLAS_GEMM_QUANT_DISPATCH MlasGemm8X8DispatchPOWER10; +#if defined(MLAS_TARGET_WASM_RELAXED_SIMD) +extern bool HasUSDot(); +#endif + // // Symmetric quantized qgemm dispatch structure // @@ -1043,7 +1048,10 @@ extern const MLAS_FPQ4GEMM_DISPATCH MlasFpQ4GemmDispatchAvx512; struct MLAS_QNBIT_GEMM_DISPATCH; -extern const MLAS_QNBIT_GEMM_DISPATCH MlasSQNBitGemmDispatchNeon; +const MLAS_QNBIT_GEMM_DISPATCH& +GetMlasQNBitGemmDispatchNeon( + bool InitializeWithDotSupport +); extern const MLAS_QNBIT_GEMM_DISPATCH MlasSQNBitGemmDispatchAvx2; @@ -1070,6 +1078,10 @@ extern const MLAS_HGEMM_DISPATCH MlasHGemmDispatchNeon; struct MLAS_SOFTMAX_DISPATCH; extern const MLAS_SOFTMAX_DISPATCH MlasSoftmaxDispatchNeon; +// eltwise dispatch structure +struct MLAS_ELTWISE_DISPATCH; +extern const MLAS_ELTWISE_DISPATCH MlasEltwiseDispatchNeon; + // // Quantized depthwise convolution kernels. // @@ -1233,6 +1245,7 @@ struct MLAS_PLATFORM { const MLAS_ROPE_DISPATCH* RopeDispatch{nullptr}; const MLAS_HGEMM_DISPATCH* HGemmDispatch{nullptr}; const MLAS_SOFTMAX_DISPATCH* SoftmaxDispatch{nullptr}; + const MLAS_ELTWISE_DISPATCH* EltwiseDispatch{nullptr}; }; inline @@ -1442,6 +1455,9 @@ MlasConvDepthwiseFloat_CHW( #endif #elif defined(MLAS_TARGET_WASM_SIMD) #define MLAS_WASM_SIMD_INTRINSICS +#if defined(MLAS_TARGET_WASM_RELAXED_SIMD) +#define MLAS_WASM_RELAXED_SIMD_INTRINSICS +#endif #elif defined(MLAS_TARGET_LARCH64) #define MLAS_LSX_INTRINSICS #endif @@ -2252,6 +2268,8 @@ MlasMaximumFloat32x4(MLAS_FLOAT32X4 Vector1, MLAS_FLOAT32X4 Vector2) #elif defined(MLAS_VSX_INTRINSICS) // Don't use vec_max to avoid undefined behavior if NAN return vec_sel(Vector2, Vector1, vec_cmpgt(Vector1, Vector2)); +#elif defined(MLAS_WASM_RELAXED_SIMD_INTRINSICS) + return wasm_f32x4_relaxed_max(Vector1, Vector2); #elif defined(MLAS_WASM_SIMD_INTRINSICS) return wasm_f32x4_max(Vector1, Vector2); #elif defined(MLAS_LSX_INTRINSICS) @@ -2272,6 +2290,8 @@ MlasMinimumFloat32x4(MLAS_FLOAT32X4 Vector1, MLAS_FLOAT32X4 Vector2) #elif defined(MLAS_VSX_INTRINSICS) // Don't use vec_min to avoid undefined behavior if NAN return vec_sel(Vector2, Vector1, vec_cmpgt(Vector2, Vector1)); +#elif defined(MLAS_WASM_RELAXED_SIMD_INTRINSICS) + return wasm_f32x4_relaxed_min(Vector1, Vector2); #elif defined(MLAS_WASM_SIMD_INTRINSICS) return wasm_f32x4_min(Vector1, Vector2); #elif defined(MLAS_LSX_INTRINSICS) diff --git a/onnxruntime/core/mlas/lib/platform.cpp b/onnxruntime/core/mlas/lib/platform.cpp index 582c1ab944b98..2165252ccd4cc 100644 --- a/onnxruntime/core/mlas/lib/platform.cpp +++ b/onnxruntime/core/mlas/lib/platform.cpp @@ -543,31 +543,25 @@ Return Value: this->SymmQgemmDispatch = &MlasSymmQgemmS8DispatchNeon; this->ConvSymU8S8Dispatch = &MlasConvSymU8DispatchNeon; this->ConvSymS8S8Dispatch = &MlasConvSymS8DispatchNeon; - this->QNBitGemmDispatch = &MlasSQNBitGemmDispatchNeon; this->RopeDispatch = &MlasRopeDispatchNeon; this->HGemmDispatch = &MlasHGemmDispatchNeon; this->SoftmaxDispatch = &MlasSoftmaxDispatchNeon; + this->EltwiseDispatch = &MlasEltwiseDispatchNeon; // // Check if the processor supports ASIMD dot product instructions. // - bool HasDotProductInstructions; - -#if defined(_WIN32) - HasDotProductInstructions = (IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE) != 0); -#else - // Use the cpuinfo value which is read from sysctl and has some additional special cases. - // https://github.com/pytorch/cpuinfo/blob/959002f82d7962a473d8bf301845f2af720e0aa4/src/arm/mach/init.c#L369-L379 + // Note: // Do NOT use ID_AA64ISAR0_EL1. It causes illegal instruction errors on Mac M1 and ARMv8-A chips // as well as failing on other ARM chips as it is an EL1 level register that requires extra // privileges to read. // // uint64_t isar0_el1; // asm("mrs %[reg], ID_AA64ISAR0_EL1\n" : [reg] "=r"(isar0_el1) : :); - // HasDotProductInstructions = ((isar0_el1 >> 44) & 0xfu) == 0x1u; - HasDotProductInstructions = MLAS_CPUIDINFO::GetCPUIDInfo().HasArmNeonDot(); -#endif + // const bool HasDotProductInstructions = ((isar0_el1 >> 44) & 0xfu) == 0x1u; + + const bool HasDotProductInstructions = MLAS_CPUIDINFO::GetCPUIDInfo().HasArmNeonDot(); if (HasDotProductInstructions) { this->GemmU8U8Dispatch = &MlasGemmU8X8DispatchUdot; @@ -578,6 +572,8 @@ Return Value: this->ConvSymS8S8Dispatch = &MlasConvSymS8DispatchDot; } + this->QNBitGemmDispatch = &GetMlasQNBitGemmDispatchNeon(HasDotProductInstructions); + #if defined(__linux__) // // Check if the processor supports ASIMD I8MM instructions. diff --git a/onnxruntime/core/mlas/lib/qgemm.cpp b/onnxruntime/core/mlas/lib/qgemm.cpp index 859fcd049ac7d..f5b33d2a9ad34 100644 --- a/onnxruntime/core/mlas/lib/qgemm.cpp +++ b/onnxruntime/core/mlas/lib/qgemm.cpp @@ -144,14 +144,7 @@ MlasGemmBatch( const double Complexity = double(M) * double(N) * double(K) * double(BatchN); - ptrdiff_t TargetThreadCount; - - if (Complexity < double(MLAS_QGEMM_THREAD_COMPLEXITY * GetMlasPlatform().MaximumThreadCount)) { - TargetThreadCount = ptrdiff_t(Complexity / double(MLAS_QGEMM_THREAD_COMPLEXITY)) + 1; - } else { - TargetThreadCount = GetMlasPlatform().MaximumThreadCount; - } - + ptrdiff_t TargetThreadCount = ptrdiff_t(Complexity / double(MLAS_QGEMM_THREAD_COMPLEXITY)) + 1; ptrdiff_t MaximumThreadCount = MlasGetMaximumThreadCount(ThreadPool); if (TargetThreadCount >= MaximumThreadCount) { @@ -308,7 +301,7 @@ size_t MLASCALL MlasGemmPackBSize( size_t N, - size_t K, + size_t K, bool AIsSigned, bool BIsSigned ) @@ -479,7 +472,7 @@ size_t MLASCALL MlasSymmQgemmPackBSize( size_t N, - size_t K, + size_t K, bool AIsSigned ) { diff --git a/onnxruntime/core/mlas/lib/qgemm.h b/onnxruntime/core/mlas/lib/qgemm.h index bcd878efa681b..596267c3abdff 100644 --- a/onnxruntime/core/mlas/lib/qgemm.h +++ b/onnxruntime/core/mlas/lib/qgemm.h @@ -886,6 +886,14 @@ MlasGemmQuantGetDispatch( if(BIsSigned || !AIsSigned) { GemmQuantDispatch = &MlasGemmU8X8DispatchNeon; } +#elif defined(MLAS_TARGET_WASM_RELAXED_SIMD) + if (!AIsSigned) { + if (HasUSDot()) { + GemmQuantDispatch = &MlasGemmU8X8DispatchWasmRelaxedSimd; + } else { + GemmQuantDispatch = &MlasGemmU8X8DispatchWasmSimd; + } + } #elif defined(MLAS_TARGET_WASM_SIMD) if (!AIsSigned) { GemmQuantDispatch = &MlasGemmU8X8DispatchWasmSimd; diff --git a/onnxruntime/core/mlas/lib/qgemm_kernel_wasmrelaxedsimd.cpp b/onnxruntime/core/mlas/lib/qgemm_kernel_wasmrelaxedsimd.cpp new file mode 100644 index 0000000000000..a3a0fa758d377 --- /dev/null +++ b/onnxruntime/core/mlas/lib/qgemm_kernel_wasmrelaxedsimd.cpp @@ -0,0 +1,563 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the MIT License. + +Module Name: + + qgemm_kernel_wasmrelaxedsimd.cpp + +Abstract: + + This module implements QGEMM kernel for WebAssembly Relaxed SIMD128. + +--*/ + +#include "mlasi.h" +#include "qgemm.h" + +bool HasUSDot() { +// Check out-of-bounds behavior of Relaxed Integer Dot Product with Accumulation with signed and unsigned input (e.g. vpdpbusd). + const v128_t int8_input = wasm_i8x16_const(0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0); + const volatile v128_t xint8_input = wasm_i8x16_const(0, 0, 0, -128, 0, 0, -128, 0, 0, -128, 0, 0, -128, 0, 0, 0); // volatile to confuse Clang which otherwise ICE's + const v128_t xint8_output = wasm_i32x4_relaxed_dot_i8x16_i7x16_add(int8_input, xint8_input, wasm_i8x16_const_splat(0)); + + const volatile v128_t overflow_input = wasm_i8x16_const(-128, -128, -128, -128, -128, -128, -1, -1, -1, -1, -128, -128, -1, -1, -1, -1); // volatile to confuse Clang which otherwise ICE's + const v128_t overflow_output = wasm_i32x4_relaxed_dot_i8x16_i7x16_add(wasm_i8x16_const_splat(-128), overflow_input, wasm_i8x16_const_splat(0)); + return !wasm_v128_any_true(wasm_v128_or( + wasm_v128_xor(xint8_output, wasm_i32x4_const_splat(128)), + wasm_v128_xor(overflow_output, wasm_i32x4_const(-65536, -98048, -98048, -130560)))); +} + +// wasm implementation of "_mm_unpacklo_epi8" +v128_t __attribute__((__always_inline__, __nodebug__)) wasm_i8x16_unpacklo_relaxed(v128_t a, v128_t b) { + return wasm_i8x16_shuffle(a, b, 0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23); +} + +// wasm implementation of "_mm_unpacklo_epi16" +v128_t __attribute__((__always_inline__, __nodebug__)) wasm_i16x8_unpacklo_relaxed(v128_t a, v128_t b) { + return wasm_i8x16_shuffle(a, b, 0, 1, 16, 17, 2, 3, 18, 19, 4, 5, 20, 21, 6, 7, 22, 23); +} + +// wasm implementation of "_mm_unpackhi_epi16" +v128_t __attribute__((__always_inline__, __nodebug__)) wasm_i16x8_unpackhi_relaxed(v128_t a, v128_t b) { + return wasm_i8x16_shuffle(a, b, 8, 9, 24, 25, 10, 11, 26, 27, 12, 13, 28, 29, 14, 15, 30, 31); +} + +struct MLAS_GEMM_U8X8_KERNEL_WASMRELAXEDSIMD +{ + typedef uint8_t PackedAType; + typedef uint8_t PackedBType; + typedef uint8_t OffsetAType; + typedef int8_t OffsetBType; + + static constexpr size_t PackedK = 4; + static constexpr MLAS_GEMM_QUANT_STRIDES Strides{ 12, 128, 128 }; + static constexpr MLAS_GEMM_QUANT_STRIDES PackedStrides{0, 0, 0}; +}; + +constexpr size_t MLAS_GEMM_U8X8_KERNEL_WASMRELAXEDSIMD::PackedK; +constexpr MLAS_GEMM_QUANT_STRIDES MLAS_GEMM_U8X8_KERNEL_WASMRELAXEDSIMD::Strides; + +template<> +MLAS_FORCEINLINE +int32_t +MlasGemmQuantFixupZeroPointB( + int32_t ZeroPointB, + bool BIsSigned + ) +{ + if (!BIsSigned) { + ZeroPointB = MLAS_GEMM_U8X8_KERNEL_WASMRELAXEDSIMD::OffsetBType(ZeroPointB ^ 0x80); + } + + return ZeroPointB; +} + +template<> +void +MlasGemmQuantCopyPackA( + MLAS_GEMM_U8X8_KERNEL_WASMRELAXEDSIMD::PackedAType* D, + const uint8_t* A, + size_t lda, + size_t CountM, + size_t CountK, + int32_t* RowSumBuffer, + bool AIsSigned + ) +{ + MLAS_UNREFERENCED_PARAMETER(AIsSigned); + const v128_t ZeroVector = wasm_i64x2_const(0, 0); + const v128_t OnesWordBroadcast = wasm_i16x8_splat(1); + uint8_t PaddedMatrixAData[8] = { 0 }; + + // + // Process a single row of matrix A in a loop. + // + + while (CountM > 0) { + + const uint8_t* a = A; + size_t k = CountK; + v128_t ReductionVector = ZeroVector; + + // + // Copy the source bytes to the packed buffer. + // + // The packed buffer has the same data ordering as the source bytes, + // but CountK is aligned up to a multiple of 4 to maintain 32-bit + // alignment. All extra bytes are zero-padded. + // + // Zero extend the source bytes to 16-bits and accumulate + // into an intermediate per-row + // accumulator. CountK cannot be greater than 128 to avoid overflowing + // these signed 16-bit accumulators. + // + + while (k >= 8) { + + v128_t Bytes = wasm_v128_load64_zero(&a[0]); + v128_t Words = wasm_i8x16_unpacklo_relaxed(Bytes, ZeroVector); + + ReductionVector = wasm_i16x8_add(ReductionVector, Words); + + wasm_v128_store64_lane(&D[0], Bytes, 0); + + a += 8; + D += 8; + k -= 8; + } + + if (k > 0) { + + // + // Copy the remaining bytes to the zero padded stack buffer. + // + + uint8_t* padded = PaddedMatrixAData; + uint8_t* padded_end = padded + k; + + do { + padded[0] = a[0]; + padded++; + a++; + } while (padded < padded_end); + + v128_t Bytes = wasm_v128_load64_zero(PaddedMatrixAData); + v128_t Words = wasm_i8x16_unpacklo_relaxed(Bytes, ZeroVector); + + ReductionVector = wasm_i16x8_add(ReductionVector, Words); + + // + // Copy quads of 8-bit values from the vector to the packed + // buffer and rotate the vector for the next iteration. + // + + for (size_t quads = (k + 3) / 4; quads > 0; quads--) { + *((int32_t*)D) = wasm_i32x4_extract_lane(Bytes, 0); + D += 4; + Bytes = wasm_i32x4_shuffle(Bytes, wasm_i32x4_splat(0), 1, 2, 3, 0); + } + } + + // + // Reduce the partial accumulators. + // + + ReductionVector = wasm_i32x4_dot_i16x8(ReductionVector, OnesWordBroadcast); + ReductionVector = wasm_i32x4_add(ReductionVector, + wasm_i32x4_shuffle(ReductionVector, wasm_i32x4_splat(0), 2, 3, 2, 3)); + ReductionVector = wasm_i32x4_add(ReductionVector, + wasm_i32x4_shuffle(ReductionVector, wasm_i32x4_splat(0), 1, 0, 1, 0)); + + *RowSumBuffer++ = wasm_i32x4_extract_lane(ReductionVector, 0); + + A += lda; + CountM -= 1; + } +} + + +MLAS_FORCEINLINE +void +MlasGemmU8X8CopyPackBProcessWasmRelaxedSimd( + MLAS_GEMM_U8X8_KERNEL_WASMRELAXEDSIMD::PackedBType* D, + v128_t BytesRow0, + v128_t BytesRow1, + v128_t BytesRow2, + v128_t BytesRow3, + v128_t BitFlipVector, + v128_t OnesByteBroadcast, + v128_t ColumnSums[2] +) +{ + v128_t PairsInterleaved0 = wasm_i8x16_unpacklo_relaxed(BytesRow0, BytesRow1); + v128_t PairsInterleaved1 = wasm_i8x16_unpacklo_relaxed(BytesRow2, BytesRow3); + + PairsInterleaved0 = wasm_v128_xor(PairsInterleaved0, BitFlipVector); + PairsInterleaved1 = wasm_v128_xor(PairsInterleaved1, BitFlipVector); + + v128_t QuadsInterleaved0 = wasm_i16x8_unpacklo_relaxed(PairsInterleaved0, PairsInterleaved1); + v128_t QuadsInterleaved1 = wasm_i16x8_unpackhi_relaxed(PairsInterleaved0, PairsInterleaved1); + + ColumnSums[0] = wasm_i32x4_relaxed_dot_i8x16_i7x16_add(QuadsInterleaved0, OnesByteBroadcast, ColumnSums[0]); + ColumnSums[1] = wasm_i32x4_relaxed_dot_i8x16_i7x16_add(QuadsInterleaved1, OnesByteBroadcast, ColumnSums[1]); + + wasm_v128_store(&D[0], QuadsInterleaved0); + wasm_v128_store(&D[16], QuadsInterleaved1); +} + +template<> +void +MlasGemmQuantCopyPackB( + MLAS_GEMM_U8X8_KERNEL_WASMRELAXEDSIMD::PackedBType* D, + const uint8_t* B, + size_t ldb, + size_t CountN, + size_t CountK, + int32_t* ColumnSumBuffer, + bool BIsSigned + ) +{ + const v128_t OnesByteBroadcast = wasm_i8x16_splat(1); + const v128_t BitFlipVector = wasm_i32x4_splat(BIsSigned ? 0 : 0x80808080); + + // + // Process 8 columns of matrix B in a loop. + // + + while (CountN >= 8) { + + const uint8_t* b = B; + size_t k = CountK; + v128_t ColumnSums[2]; + + ColumnSums[0] = wasm_i64x2_const(0, 0); + ColumnSums[1] = wasm_i64x2_const(0, 0); + + // + // Interleave rows of matrix B and write to the packed buffer. + // + + while (k >= MLAS_GEMM_U8X8_KERNEL_WASMRELAXEDSIMD::PackedK) { + + v128_t BytesRow0 = wasm_v128_load64_zero(&b[0]); + v128_t BytesRow1 = wasm_v128_load64_zero(&b[ldb]); + v128_t BytesRow2 = wasm_v128_load64_zero(&b[ldb * 2]); + v128_t BytesRow3 = wasm_v128_load64_zero(&b[ldb * 3]); + + MlasGemmU8X8CopyPackBProcessWasmRelaxedSimd(D, BytesRow0, BytesRow1, BytesRow2, BytesRow3, BitFlipVector, OnesByteBroadcast, ColumnSums); + + b += ldb * 4; + D += 32; + k -= 4; + } + + if (k > 0) { + + v128_t BytesRow0 = wasm_v128_load64_zero(&b[0]); + v128_t BytesRow1 = BitFlipVector; + v128_t BytesRow2 = BitFlipVector; + v128_t BytesRow3 = BitFlipVector; + + if (k >= 2) { + BytesRow1 = wasm_v128_load64_zero(&b[ldb]); + } + + if (k >= 3) { + BytesRow2 = wasm_v128_load64_zero(&b[ldb * 2]); + } + + MlasGemmU8X8CopyPackBProcessWasmRelaxedSimd(D, BytesRow0, BytesRow1, BytesRow2, BytesRow3, BitFlipVector, OnesByteBroadcast, ColumnSums); + + D += 32; + } + + wasm_v128_store(&ColumnSumBuffer[0], ColumnSums[0]); + wasm_v128_store(&ColumnSumBuffer[4], ColumnSums[1]); + ColumnSumBuffer += 8; + + B += 8; + CountN -= 8; + } + + // + // Process the remaining columns of matrix B. + // + + if (CountN > 0) { + + const uint8_t* b = B; + size_t k = CountK; + v128_t ColumnSums[2]; + uint8_t PaddedMatrixBData[32]; + + wasm_v128_store(&PaddedMatrixBData[0], BitFlipVector); + wasm_v128_store(&PaddedMatrixBData[16], BitFlipVector); + + ColumnSums[0] = wasm_i64x2_const(0, 0); + ColumnSums[1] = wasm_i64x2_const(0, 0); + + // + // Interleave rows of matrix B using an intermediate zero padded stack + // buffer and write to the packed buffer. + // + + while (k >= MLAS_GEMM_U8X8_KERNEL_WASMRELAXEDSIMD::PackedK) { + + const uint8_t* bcopy = b; + uint8_t* padded = PaddedMatrixBData; + uint8_t* padded_end = padded + CountN; + + do { + padded[0] = bcopy[0]; + padded[8] = bcopy[ldb]; + padded[16] = bcopy[ldb * 2]; + padded[24] = bcopy[ldb * 3]; + padded++; + bcopy++; + } while (padded < padded_end); + + v128_t BytesRow0 = wasm_v128_load64_zero(&PaddedMatrixBData[0]); + v128_t BytesRow1 = wasm_v128_load64_zero(&PaddedMatrixBData[8]); + v128_t BytesRow2 = wasm_v128_load64_zero(&PaddedMatrixBData[16]); + v128_t BytesRow3 = wasm_v128_load64_zero(&PaddedMatrixBData[24]); + + MlasGemmU8X8CopyPackBProcessWasmRelaxedSimd(D, BytesRow0, BytesRow1, BytesRow2, BytesRow3, BitFlipVector, OnesByteBroadcast, ColumnSums); + + b += ldb * 4; + D += 32; + k -= 4; + } + + if (k > 0) { + + const uint8_t* bcopy = b; + uint8_t* padded = PaddedMatrixBData; + uint8_t* padded_end = padded + CountN; + + wasm_v128_store(&PaddedMatrixBData[0], BitFlipVector); + wasm_v128_store(&PaddedMatrixBData[16], BitFlipVector); + + if (k == 3) { + do { + padded[0] = bcopy[0]; + padded[8] = bcopy[ldb]; + padded[16] = bcopy[ldb * 2]; + padded++; + bcopy++; + } while (padded < padded_end); + } else if (k == 2) { + do { + padded[0] = bcopy[0]; + padded[8] = bcopy[ldb]; + padded++; + bcopy++; + } while (padded < padded_end); + } else { + do { + padded[0] = bcopy[0]; + padded++; + bcopy++; + } while (padded < padded_end); + } + + v128_t BytesRow0 = wasm_v128_load64_zero(&PaddedMatrixBData[0]); + v128_t BytesRow1 = wasm_v128_load64_zero(&PaddedMatrixBData[8]); + v128_t BytesRow2 = wasm_v128_load64_zero(&PaddedMatrixBData[16]); + v128_t BytesRow3 = wasm_v128_load64_zero(&PaddedMatrixBData[24]); + + MlasGemmU8X8CopyPackBProcessWasmRelaxedSimd(D, BytesRow0, BytesRow1, BytesRow2, BytesRow3, BitFlipVector, OnesByteBroadcast, ColumnSums); + } + + wasm_v128_store(&ColumnSumBuffer[0], ColumnSums[0]); + wasm_v128_store(&ColumnSumBuffer[4], ColumnSums[1]); + } +} + +MLAS_FORCEINLINE +void +MlasGemmU8X8MultiplyAccumulateRowWasmRelaxedSimd( + v128_t ABroadcast, + const uint8_t* B, + v128_t Accumulators[2] +) +{ + v128_t BElements0 = wasm_v128_load(&B[0]); + v128_t BElements1 = wasm_v128_load(&B[16]); + + Accumulators[0] = wasm_i32x4_relaxed_dot_i8x16_i7x16_add(BElements0, ABroadcast, Accumulators[0]); + Accumulators[1] = wasm_i32x4_relaxed_dot_i8x16_i7x16_add(BElements1, ABroadcast, Accumulators[1]); +} + + +template<> +size_t +MlasGemmQuantKernel( + const MLAS_GEMM_U8X8_KERNEL_WASMRELAXEDSIMD::PackedAType* A, + const MLAS_GEMM_U8X8_KERNEL_WASMRELAXEDSIMD::PackedBType* B, + int32_t* C, + size_t PackedCountK, + size_t CountM, + size_t CountN, + size_t ldc, + const int32_t* RowSumBuffer, + const int32_t* ColumnSumBuffer, + const int32_t* ZeroPointB, + bool ZeroMode + ) +{ + MLAS_UNREFERENCED_PARAMETER(CountM); + MLAS_UNREFERENCED_PARAMETER(ldc); + + while (CountN > 0) { + + v128_t Accumulators[2]; + + // + // Initialize the accumulators with the row and column sums. + // + + int32_t RowSumValue = RowSumBuffer[0]; + + if (ZeroPointB != nullptr) { + + int32_t ScaledRowSumBuffer[8]; + + for (size_t i = 0; i < 8; i++) { + ScaledRowSumBuffer[i] = RowSumValue * ZeroPointB[i]; + } + + ZeroPointB += 8; + + Accumulators[0] = wasm_v128_load(&ScaledRowSumBuffer[0]); + Accumulators[1] = wasm_v128_load(&ScaledRowSumBuffer[4]); + + } + else { + + Accumulators[0] = wasm_i32x4_splat(RowSumValue); + Accumulators[1] = Accumulators[0]; + } + + Accumulators[0] = wasm_i32x4_add(Accumulators[0], wasm_v128_load(&ColumnSumBuffer[0])); + Accumulators[1] = wasm_i32x4_add(Accumulators[1], wasm_v128_load(&ColumnSumBuffer[4])); + ColumnSumBuffer += 8; + + // + // Broadcast each pair of 16-bit values from the matrix A and multiply + // with the pair of 16-bit values from matrix B, and add the 32-bit + // intermediate into the accumulator registers. + // + + const uint8_t* a = A; + size_t k = PackedCountK; + + while (k >= 4) { + + v128_t AElements = wasm_v128_load((v128_t*)a); + v128_t ABroadcast; + + ABroadcast = wasm_i32x4_shuffle(AElements, wasm_i32x4_splat(0), 0, 0, 0, 0); + MlasGemmU8X8MultiplyAccumulateRowWasmRelaxedSimd(ABroadcast, &B[0], Accumulators); + + ABroadcast = wasm_i32x4_shuffle(AElements, wasm_i32x4_splat(0), 1, 1, 1, 1); + MlasGemmU8X8MultiplyAccumulateRowWasmRelaxedSimd(ABroadcast, &B[32], Accumulators); + + ABroadcast = wasm_i32x4_shuffle(AElements, wasm_i32x4_splat(0), 2, 2, 2, 2); + MlasGemmU8X8MultiplyAccumulateRowWasmRelaxedSimd(ABroadcast, &B[64], Accumulators); + + ABroadcast = wasm_i32x4_shuffle(AElements, wasm_i32x4_splat(0), 3, 3, 3, 3); + MlasGemmU8X8MultiplyAccumulateRowWasmRelaxedSimd(ABroadcast, &B[96], Accumulators); + + a += 4 * 4; + B += 4 * 32; + k -= 4; + } + + while (k > 0) { + + v128_t ABroadcast = wasm_i32x4_splat(*((int32_t*)a)); + MlasGemmU8X8MultiplyAccumulateRowWasmRelaxedSimd(ABroadcast, &B[0], Accumulators); + + a += 4; + B += 32; + k -= 1; + } + + // + // Output the accumulator block after optionally accumulating the values + // from matrix C. + // + + if (CountN >= 8) { + + if (!ZeroMode) { + Accumulators[0] = wasm_i32x4_add(Accumulators[0], wasm_v128_load(&C[0])); + Accumulators[1] = wasm_i32x4_add(Accumulators[1], wasm_v128_load(&C[4])); + } + + wasm_v128_store(&C[0], Accumulators[0]); + wasm_v128_store(&C[4], Accumulators[1]); + + C += 8; + CountN -= 8; + + } + else { + + // + // Output the remaining partial output block. + // + + if ((CountN & 4) != 0) { + + if (!ZeroMode) { + Accumulators[0] = wasm_i32x4_add(Accumulators[0], wasm_v128_load(&C[0])); + } + + wasm_v128_store(&C[0], Accumulators[0]); + C += 4; + + Accumulators[0] = Accumulators[1]; + } + + if ((CountN & 2) != 0) { + + if (!ZeroMode) { + Accumulators[0] = wasm_i32x4_add(Accumulators[0], wasm_v128_load64_zero(&C[0])); + } + + wasm_v128_store64_lane(&C[0], Accumulators[0], 0); + C += 2; + + Accumulators[0] = wasm_i32x4_shuffle(Accumulators[0], wasm_i32x4_splat(0), 2, 3, 2, 3); + } + + if ((CountN & 1) != 0) { + + int32_t AccumulatorValue = wasm_i32x4_extract_lane(Accumulators[0], 0); + + if (!ZeroMode) { + AccumulatorValue += C[0]; + } + + C[0] = AccumulatorValue; + } + + CountN = 0; + } + } + + return 1; +} + +const MLAS_GEMM_QUANT_DISPATCH MlasGemmU8X8DispatchWasmRelaxedSimd = { + MlasGemmQuantOperation, + nullptr, + nullptr, + MLAS_GEMM_U8X8_KERNEL_WASMRELAXEDSIMD::PackedK, + 0, + 4 // multiple of kernel stride M +}; diff --git a/onnxruntime/core/mlas/lib/qnbitgemm.cpp b/onnxruntime/core/mlas/lib/qnbitgemm.cpp index f064a8e1d6a78..eafe91575c528 100644 --- a/onnxruntime/core/mlas/lib/qnbitgemm.cpp +++ b/onnxruntime/core/mlas/lib/qnbitgemm.cpp @@ -91,6 +91,7 @@ MlasIsQNBitGemmAvailable( } case SQNBitGemmVariant_BitWidth4_CompInt8: { // SQ4BitGemmKernel_BlkSum_CompInt8 return + (Dispatch->SQ4BitGemmKernel_Packed_CompInt8 != nullptr && Dispatch->QuantizeA_Packed_CompInt8 != nullptr) || (Dispatch->SQ4BitGemmKernel_CompInt8 != nullptr && Dispatch->QuantizeARow_CompInt8 != nullptr) || (Dispatch->SQ4BitGemmKernel_BlkSum_CompInt8 != nullptr && Dispatch->QuantizeARowComputeBlkSum_CompInt8 != nullptr); } @@ -110,6 +111,7 @@ QNBitGemmPerGemmWorkspaceSize( size_t K, size_t BlkBitWidth, size_t BlkLen, + bool HasZeroPoint, MLAS_QNBIT_GEMM_COMPUTE_TYPE ComputeType ) { @@ -119,7 +121,7 @@ QNBitGemmPerGemmWorkspaceSize( } if (BlkBitWidth == 4 && Dispatch->Q4BitGemmPerGemmWorkspaceSize != nullptr) { - return Dispatch->Q4BitGemmPerGemmWorkspaceSize(M, N, K, BlkLen, ComputeType); + return Dispatch->Q4BitGemmPerGemmWorkspaceSize(M, N, K, BlkLen, HasZeroPoint, ComputeType); } return 0; @@ -151,10 +153,11 @@ QNBitGemmPerGemmWorkspaceStride( size_t K, size_t BlkBitWidth, size_t BlkLen, + bool HasZeroPoint, MLAS_QNBIT_GEMM_COMPUTE_TYPE ComputeType ) { - const auto Size = QNBitGemmPerGemmWorkspaceSize(M, N, K, BlkBitWidth, BlkLen, ComputeType); + const auto Size = QNBitGemmPerGemmWorkspaceSize(M, N, K, BlkBitWidth, BlkLen, HasZeroPoint, ComputeType); const auto Alignment = QNBitGemmPerGemmWorkspaceAlignment(BlkBitWidth, BlkLen, ComputeType); return MlasDivRoundup(Size, Alignment) * Alignment; } @@ -169,10 +172,12 @@ MlasQNBitGemmBatchWorkspaceSize( size_t BatchN, size_t BlkBitWidth, size_t BlkLen, + bool HasZeroPoint, MLAS_QNBIT_GEMM_COMPUTE_TYPE ComputeType ) { - const size_t PerGemmWorkspaceStride = QNBitGemmPerGemmWorkspaceStride(M, N, K, BlkBitWidth, BlkLen, ComputeType); + const size_t PerGemmWorkspaceStride = + QNBitGemmPerGemmWorkspaceStride(M, N, K, BlkBitWidth, BlkLen, HasZeroPoint, ComputeType); if (PerGemmWorkspaceStride == 0) { return 0; } @@ -190,6 +195,7 @@ MlasQNBitGemmPackQuantBDataSize( size_t K, size_t BlkBitWidth, size_t BlkLen, + bool HasZeroPoint, MLAS_QNBIT_GEMM_COMPUTE_TYPE ComputeType ) { @@ -200,7 +206,7 @@ MlasQNBitGemmPackQuantBDataSize( if (BlkBitWidth == 4 && Dispatch->Q4BitGemmPackQuantBDataSize != nullptr) { return Dispatch->Q4BitGemmPackQuantBDataSize( - N, K, BlkLen, ComputeType + N, K, BlkLen, HasZeroPoint, ComputeType ); } @@ -232,7 +238,7 @@ MlasQNBitGemmPackQuantBData( const void* QuantBData, void* PackedQuantBDataAndOrBlkSumWorkspace, const void* QuantBScale, - bool has_zp_input, + bool HasZeroPoint, const void* QuantBZeroPoint, MLAS_THREADPOOL* ThreadPool ) @@ -253,7 +259,7 @@ MlasQNBitGemmPackQuantBData( ComputeType, static_cast(QuantBData), static_cast(QuantBScale), - has_zp_input, + HasZeroPoint, static_cast(QuantBZeroPoint), packed_quant_b, ThreadPool @@ -286,6 +292,29 @@ MlasQNBitGemmPackQuantBData( } } +bool MLASCALL +MlasQNBitGemmScalesPacked( + size_t K, + size_t BlkBitWidth, + size_t BlkLen, + MLAS_QNBIT_GEMM_COMPUTE_TYPE ComputeType, + bool HasZeroPoint +) { +#ifdef MLAS_TARGET_ARM64 + if (BlkBitWidth == 4 && ComputeType == SQNBIT_CompInt8) { + const auto UsePacked = GetMlasPlatform().QNBitGemmDispatch->UsePacked_CompInt8; + return UsePacked && UsePacked(K, BlkLen, HasZeroPoint); + } +#else + MLAS_UNREFERENCED_PARAMETER(K); + MLAS_UNREFERENCED_PARAMETER(BlkBitWidth); + MLAS_UNREFERENCED_PARAMETER(BlkLen); + MLAS_UNREFERENCED_PARAMETER(ComputeType); + MLAS_UNREFERENCED_PARAMETER(HasZeroPoint); +#endif // MLAS_TARGET_ARM64 + return false; +} + namespace { @@ -519,6 +548,16 @@ SQ4BitGemm_CompInt8( const size_t RangeCountN ) { + const auto UsePacked = GetMlasPlatform().QNBitGemmDispatch->UsePacked_CompInt8; + const auto SQ4BitGemm = GetMlasPlatform().QNBitGemmDispatch->SQ4BitGemmKernel_Packed_CompInt8; + if (UsePacked && SQ4BitGemm && UsePacked(K, BlkLen, DataParams->QuantBZeroPoint)) { + const std::byte* QuantA = static_cast(PerGemmWorkspace); + SQ4BitGemm(BlkLen, QuantA, DataParams->PackedQuantBData, + DataParams->C, RangeStartM, RangeCountM, RangeStartN, RangeCountN, K, + DataParams->ldc, DataParams->Bias); + return; + } + #ifdef MLAS_TARGET_AMD64_IX86 PerGemmQuantAWorkspace* const per_gemm_quant_a_workspace = static_cast(PerGemmWorkspace); constexpr size_t BlkBitWidth = 4; @@ -666,6 +705,8 @@ InitializeWorkspace_CompInt8( { MLAS_UNREFERENCED_PARAMETER(N); + const auto UsePacked = GetMlasPlatform().QNBitGemmDispatch->UsePacked_CompInt8; + const auto QuantizeA_Packed = GetMlasPlatform().QNBitGemmDispatch->QuantizeA_Packed_CompInt8; const auto QuantizeARow = GetMlasPlatform().QNBitGemmDispatch->QuantizeARow_CompInt8; const auto QuantizeARow2 = GetMlasPlatform().QNBitGemmDispatch->QuantizeARowComputeBlkSum_CompInt8; @@ -673,7 +714,15 @@ InitializeWorkspace_CompInt8( const size_t QuantAStride = BlockCountK * Q8BlkSize(BlkLen); // TODO: try parallel on BatchN * M threads because BatchN is usually 1. - if (QuantizeARow) { + if (UsePacked && QuantizeA_Packed && UsePacked(K, BlkLen, DataParams->QuantBZeroPoint)) { + MlasTrySimpleParallel(ThreadPool, BatchN, [&](ptrdiff_t gemm_idx) { + const auto& data = DataParams[gemm_idx]; + + const float* ARowPtr = data.A; + std::byte* QuantARowPtr = static_cast(Workspace) + gemm_idx * PerGemmWorkspaceStride; + QuantizeA_Packed(BlkLen, ARowPtr, M, K, QuantARowPtr); + }); + } else if (QuantizeARow) { MlasTrySimpleParallel(ThreadPool, BatchN, [&](ptrdiff_t gemm_idx) { const auto& data = DataParams[gemm_idx]; @@ -844,7 +893,9 @@ MlasQNBitGemmBatch( ); } - const size_t PerGemmWorkspaceStride = QNBitGemmPerGemmWorkspaceStride(M, N, K, BlkBitWidth, BlkLen, ComputeType); + const bool has_zp_input = DataParams->QuantBZeroPoint; + const size_t PerGemmWorkspaceStride = + QNBitGemmPerGemmWorkspaceStride(M, N, K, BlkBitWidth, BlkLen, has_zp_input, ComputeType); if (const auto InitializeWorkspaceOperation = GetInitializeWorkspace(Variant); InitializeWorkspaceOperation != nullptr) { @@ -862,7 +913,7 @@ MlasQNBitGemmBatch( const auto* Data = &DataParams[gemm_i]; void* PerGemmWorkspace = reinterpret_cast(Workspace) + gemm_i * PerGemmWorkspaceStride; - if (ComputeType == SQNBIT_CompInt8 && GetMlasPlatform().QNBitGemmDispatch->SQ4BitGemmPackQuantBDataAndBlkSum != nullptr) { + if (ComputeType == SQNBIT_CompInt8 && GetMlasPlatform().QNBitGemmDispatch->SQ4BitGemmKernel_BlkSum_CompInt8 != nullptr) { PackedQuantBDataStruct packed_quant_b(const_cast(Data->QuantBDataWorkspace), N, BlockCountK, BlkLen); const_cast*>(Data)->PackedQuantBData = packed_quant_b.PackedQuantBData; const_cast*>(Data)->QuantBBlkSum = packed_quant_b.QuantBBlkSum; @@ -933,7 +984,7 @@ MlasQNBitGemmBatch( void* PerGemmWorkspace = reinterpret_cast(Workspace) + gemm_i * PerGemmWorkspaceStride; - if (ComputeType == SQNBIT_CompInt8 && GetMlasPlatform().QNBitGemmDispatch->SQ4BitGemmPackQuantBDataAndBlkSum != nullptr) { + if (ComputeType == SQNBIT_CompInt8 && GetMlasPlatform().QNBitGemmDispatch->SQ4BitGemmKernel_BlkSum_CompInt8 != nullptr) { PackedQuantBDataStruct packed_quant_b(const_cast(Data->QuantBDataWorkspace), N, BlockCountK, BlkLen); const_cast*>(Data)->PackedQuantBData = packed_quant_b.PackedQuantBData; const_cast*>(Data)->QuantBBlkSum = packed_quant_b.QuantBBlkSum; diff --git a/onnxruntime/core/mlas/lib/qnbitgemm.h b/onnxruntime/core/mlas/lib/qnbitgemm.h index eb3d0b44ae3de..e25455cbfa217 100644 --- a/onnxruntime/core/mlas/lib/qnbitgemm.h +++ b/onnxruntime/core/mlas/lib/qnbitgemm.h @@ -55,9 +55,12 @@ struct PackedQuantBDataStruct { constexpr size_t BlkBitWidth = 4; const size_t PackedQuantBDataSize = N * BlockCountK * MlasQNBitBlkDataSizeInBytes(BlkBitWidth, BlkLen); size_t BlkSumSize = MlasDivRoundup(N, 16) * BlockCountK * 16 * sizeof(T); - +#if defined(MLAS_TARGET_AMD64_IX86) // _mm256_load_si256 requires alignment on a 32-byte boundary PackedQuantBData = (std::byte*)MlasAlignAddress(PackedQuantBWorkspace, 32); +#else + PackedQuantBData = (std::byte*)PackedQuantBWorkspace; +#endif QuantBBlkSum = (T*)(PackedQuantBData + PackedQuantBDataSize); QuantBBlkSum = (T*)MlasAlignAddress(QuantBBlkSum, MlasQNBitQuantBBlkSumAlignment()); PackedQuantBScale = (T*)((std::byte*)QuantBBlkSum + BlkSumSize); @@ -95,6 +98,7 @@ struct MLAS_QNBIT_GEMM_DISPATCH { size_t N, size_t K, size_t BlkLen, + bool HasZeroPoint, MLAS_QNBIT_GEMM_COMPUTE_TYPE ComputeType ); @@ -121,9 +125,9 @@ struct MLAS_QNBIT_GEMM_DISPATCH { MLAS_QNBIT_GEMM_COMPUTE_TYPE ComputeType, const std::byte* QuantBDataBegin, const float* QuantBScaleBegin, - bool has_zp_input, + bool HasZeroPoint, const std::byte* QuantBZPBegin, - PackedQuantBDataStruct& packed_quant_b, + PackedQuantBDataStruct& PackedQuantB, MLAS_THREADPOOL* ThreadPool ); @@ -141,6 +145,7 @@ struct MLAS_QNBIT_GEMM_DISPATCH { * @param[in] N column size of matrix B and C * @param[in] K column size of matrix A and row size of matrix B * @param[in] BlkLen number of quantized values per block + * @param[in] HasZeroPoint whether zero points are provided * @param[in] ComputeType GEMM compute type (e.g., multiplying float or int8 values) */ typedef size_t(Q4BitGemmPerGemmWorkspaceSize_Fn)( @@ -148,6 +153,7 @@ struct MLAS_QNBIT_GEMM_DISPATCH { size_t N, size_t K, size_t BlkLen, + bool HasZeroPoint, MLAS_QNBIT_GEMM_COMPUTE_TYPE ComputeType ); @@ -267,6 +273,39 @@ struct MLAS_QNBIT_GEMM_DISPATCH { // SQNBIT_CompInt8 kernel function prototypes. // + /** + * @brief Multiply quantized 8-bit integer matrix A with quantized 4-bit integer matrix B. + * A and B are block quantized and B is column major. + * A should be packed using QuantizeA_Packed_CompInt8. + * + * @param BlkLen Number of values in a block. + * @param QuantA Supplies the quantized A matrix. + Binary data containing block quantized int8 data and scale values. + * @param PackedQuantBData Supplies the packed quantized B matrix data. + * @param[out] C Supplies the output C matrix. + * @param RangeStartM Start of M range. + * @param RangeCountM Number of rows of A and C. + * @param RangeStartN Start of N range. + * @param RangeCountN Number of columns of B and C. + * @param CountK Number of columns of A and rows of B. + * @param ldc Number of elements between adjacent rows of C. + */ + typedef void(SQ4BitGemmKernel_Packed_CompInt8_Fn)( + size_t BlkLen, + const std::byte* QuantA, + const std::byte* PackedQuantBData, + float* C, + const size_t RangeStartM, + const size_t RangeCountM, + const size_t RangeStartN, + const size_t RangeCountN, + size_t CountK, + size_t ldc, + const float* Bias + ); + + SQ4BitGemmKernel_Packed_CompInt8_Fn* SQ4BitGemmKernel_Packed_CompInt8 = nullptr; + /** * @brief Multiply quantized 8-bit integer matrix A with quantized 4-bit integer matrix B. * A and B are block quantized and B is column major. @@ -343,6 +382,38 @@ struct MLAS_QNBIT_GEMM_DISPATCH { SQ4BitGemmKernel_CompInt8_Fn* SQ4BitGemmKernel_CompInt8 = nullptr; + /** + * @brief Whether to use SQ4BitGemmKernel_Packed_CompInt8 for this problem. + */ + typedef bool(UsePacked_CompInt8_Fn)( + size_t K, + size_t BlkLen, + bool HasZp + ); + + UsePacked_CompInt8_Fn* UsePacked_CompInt8 = nullptr; + + /** + * @brief Block quantize values from matrix A from floats to quantized 8-bit integers. + * Used in conjunction with SQ4BitGemmKernel_Packed_CompInt8. + * + * @param BlkLen Number of values in a block. + * @param A Supplies the A matrix. + * @param CountM Number of rows of A. + * @param CountK Number of columns of A. + * @param[out] QuantA Supplies the output quantized A matrix. + * Binary data containing block quantized int8 data and scale values. + */ + typedef void(QuantizeA_Packed_CompInt8_Fn)( + size_t BlkLen, + const float* A, + size_t CountM, + size_t CountK, + std::byte* QuantA + ); + + QuantizeA_Packed_CompInt8_Fn* QuantizeA_Packed_CompInt8 = nullptr; + /** * @brief Block quantize values from one row of matrix A from floats to quantized 8-bit integers. * diff --git a/onnxruntime/core/mlas/lib/qnbitgemm_kernel_neon.cpp b/onnxruntime/core/mlas/lib/qnbitgemm_kernel_neon.cpp index d05de64e68ec8..ab71492805e9c 100644 --- a/onnxruntime/core/mlas/lib/qnbitgemm_kernel_neon.cpp +++ b/onnxruntime/core/mlas/lib/qnbitgemm_kernel_neon.cpp @@ -15,14 +15,23 @@ Module Name: --*/ +#include "qnbitgemm_kernel_neon.h" + #include #include +#include #include "qnbitgemm.h" -#include "qnbitgemm_kernel_neon.h" #include "sqnbitgemm_q8_block.h" +#ifdef USE_KLEIDIAI +#include "kai/kai_common.h" +#include "kai/ukernels/matmul/pack/kai_rhs_pack_nxk_qsi4c32p_qsu4c32s1s0.h" +#include "kai/ukernels/matmul/pack/kai_lhs_quant_pack_qai8dxp_f32.h" +#include "kai_ukernel_interface.h" +#endif + namespace sqnbitgemm_neon { @@ -38,16 +47,31 @@ Q4BitGemmPackQuantBDataSize( size_t N, size_t K, size_t BlkLen, + bool HasZeroPoint, MLAS_QNBIT_GEMM_COMPUTE_TYPE ComputeType ) { +#ifndef USE_KLEIDIAI + MLAS_UNREFERENCED_PARAMETER(HasZeroPoint); MLAS_UNREFERENCED_PARAMETER(ComputeType); // same size regardless of ComputeType - - constexpr size_t BlkBitWidth = 4; - - const size_t BlockCountK = MlasDivRoundup(K, BlkLen); - const size_t PackedQuantBDataSize = N * BlockCountK * MlasQNBitBlkDataSizeInBytes(BlkBitWidth, BlkLen); - return PackedQuantBDataSize; +#endif + +#ifdef USE_KLEIDIAI + if (ComputeType == SQNBIT_CompInt8 && UseKleidiAI(K, BlkLen, HasZeroPoint)) { + const kai_matmul_clamp_f32_qai8dxp_qsi4c32p_ukernel& ukernel = GetKleidiAIGemmUKernel(); + const size_t nr = ukernel.get_nr(); + const size_t kr = ukernel.get_kr(); + const size_t sr = ukernel.get_sr(); + return kai_get_rhs_packed_size_rhs_pack_nxk_qsi4c32p_qsu4c32s1s0(N, K, nr, kr, sr, BlkLen, kai_dt_bf16); + } else +#endif + { + constexpr size_t BlkBitWidth = 4; + + const size_t BlockCountK = MlasDivRoundup(K, BlkLen); + const size_t PackedQuantBDataSize = N * BlockCountK * MlasQNBitBlkDataSizeInBytes(BlkBitWidth, BlkLen); + return PackedQuantBDataSize; + } } void @@ -121,6 +145,60 @@ SQ4BitGemmPackQuantBData( ); } +void +SQ4BitGemmPackQuantBDataAndBlkSum( + size_t N, + size_t K, + size_t BlkLen, + MLAS_QNBIT_GEMM_COMPUTE_TYPE ComputeType, + const std::byte* QuantBDataBegin, + const float* QuantBScaleBegin, + bool HasZeroPoint, + const std::byte*, + PackedQuantBDataStruct& PackedQuantB, + MLAS_THREADPOOL* ThreadPool +) +{ +#ifndef USE_KLEIDIAI + MLAS_UNREFERENCED_PARAMETER(QuantBScaleBegin); + MLAS_UNREFERENCED_PARAMETER(HasZeroPoint); +#endif + assert(BlkLen >= 16 && BlkLen % 16 == 0); + +#ifdef USE_KLEIDIAI + if (UseKleidiAI(K, BlkLen, HasZeroPoint)) { + const kai_matmul_clamp_f32_qai8dxp_qsi4c32p_ukernel& ukernel = GetKleidiAIGemmUKernel(); + std::byte* PackedQuantBDataBegin = PackedQuantB.PackedQuantBData; + + const size_t nr = ukernel.get_nr(); + const size_t kr = ukernel.get_kr(); + const size_t sr = ukernel.get_sr(); + + kai_rhs_pack_nxk_qsi4c32p_qsu4c32s1s0_params params; + params.lhs_zero_point = 1; + params.rhs_zero_point = 8; + params.scale_dt = kai_dt_bf16; + + const size_t BlockCountK = MlasDivRoundup(K, BlkLen); + const size_t scales_len = N * BlockCountK; + std::vector scales(scales_len); + for (size_t i = 0; i < scales_len; i++) { + const uint32_t* i32 = reinterpret_cast(&QuantBScaleBegin[i]); + scales[i] = *i32 >> 16; + } + + kai_run_rhs_pack_nxk_qsi4c32p_qsu4c32s1s0(1, N, K, nr, kr, sr, BlkLen, + reinterpret_cast(QuantBDataBegin), BlockCountK * BlkLen / 2, + nullptr, scales.data(), BlockCountK * sizeof(uint16_t), + PackedQuantBDataBegin, 0, ¶ms); + } else +#endif + { + std::byte* PackedQuantBDataBegin = reinterpret_cast(PackedQuantB.QuantBWorkspace_); + SQ4BitGemmPackQuantBData(N, K, BlkLen, ComputeType, QuantBDataBegin, PackedQuantBDataBegin, ThreadPool); + } +} + // // Workspace size calculation function implementation. // @@ -131,17 +209,34 @@ Q4BitGemmPerGemmWorkspaceSize( size_t N, size_t K, size_t BlkLen, + bool HasZeroPoint, MLAS_QNBIT_GEMM_COMPUTE_TYPE ComputeType ) { MLAS_UNREFERENCED_PARAMETER(N); +#ifndef USE_KLEIDIAI + MLAS_UNREFERENCED_PARAMETER(HasZeroPoint); +#endif switch (ComputeType) { case SQNBIT_CompInt8: { // workspace buffer is used for block quantization of A to int8 - const size_t BlockCountK = MlasDivRoundup(K, BlkLen); - const size_t PerGemmWorkspaceSize = M * BlockCountK * Q8BlkSize(BlkLen); - return PerGemmWorkspaceSize; +#ifdef USE_KLEIDIAI + if (UseKleidiAI(K, BlkLen, HasZeroPoint)) { + const kai_matmul_clamp_f32_qai8dxp_qsi4c32p_ukernel& ukernel = + M == 1? GetKleidiAIGemvUKernel() : GetKleidiAIGemmUKernel(); + + const size_t mr = ukernel.get_mr(); + const size_t kr = ukernel.get_kr(); + const size_t sr = ukernel.get_sr(); + return kai_get_lhs_packed_size_lhs_quant_pack_qai8dxp_f32(M, K, mr, kr, sr); + } else +#endif + { + const size_t BlockCountK = MlasDivRoundup(K, BlkLen); + const size_t PerGemmWorkspaceSize = M * BlockCountK * Q8BlkSize(BlkLen); + return PerGemmWorkspaceSize; + } } default: { return 0; @@ -169,33 +264,66 @@ Q4BitGemmPerGemmWorkspaceAlignment( } // namespace +bool +UseKleidiAI(size_t K, size_t BlkLen, bool HasZp) +{ +#ifdef USE_KLEIDIAI + bool has_dotprod = MLAS_CPUIDINFO::GetCPUIDInfo().HasArmNeonDot(); + return (BlkLen % 32) == 0 && (K % BlkLen) == 0 && !HasZp && has_dotprod; +#else + MLAS_UNREFERENCED_PARAMETER(K); + MLAS_UNREFERENCED_PARAMETER(BlkLen); + MLAS_UNREFERENCED_PARAMETER(HasZp); + return false; +#endif +} + } // namespace sqnbitgemm_neon // -// Kernel dispatch structure definition. +// Kernel dispatch structure accessor. // -const MLAS_QNBIT_GEMM_DISPATCH MlasSQNBitGemmDispatchNeon = []() { - MLAS_QNBIT_GEMM_DISPATCH d; +const MLAS_QNBIT_GEMM_DISPATCH& +GetMlasQNBitGemmDispatchNeon( + bool InitializeWithDotSupport +) +{ + // Note: The InitializeWithX parameters are only used in the invocation of this method that initializes the static + // MLAS_QNBIT_GEMM_DISPATCH instance. - d.Q4BitGemmPackQuantBDataSize = sqnbitgemm_neon::Q4BitGemmPackQuantBDataSize; - d.SQ4BitGemmPackQuantBData = sqnbitgemm_neon::SQ4BitGemmPackQuantBData; + static const MLAS_QNBIT_GEMM_DISPATCH MlasQNBitGemmDispatchNeon = [&]() { + MLAS_QNBIT_GEMM_DISPATCH d; - d.Q4BitGemmPerGemmWorkspaceSize = sqnbitgemm_neon::Q4BitGemmPerGemmWorkspaceSize; - d.Q4BitGemmPerGemmWorkspaceAlignment = sqnbitgemm_neon::Q4BitGemmPerGemmWorkspaceAlignment; + d.Q4BitGemmPackQuantBDataSize = sqnbitgemm_neon::Q4BitGemmPackQuantBDataSize; + d.SQ4BitGemmPackQuantBData = sqnbitgemm_neon::SQ4BitGemmPackQuantBData; + d.SQ4BitGemmPackQuantBDataAndBlkSum = sqnbitgemm_neon::SQ4BitGemmPackQuantBDataAndBlkSum; - d.SQ4BitGemmM1Kernel_CompFp32 = sqnbitgemm_neon::SQ4BitGemmM1Kernel_CompFp32; - d.SQ4BitBlkDequantBForSgemm_CompFp32 = sqnbitgemm_neon::SQ4BitBlkDequantBForSgemm_CompFp32; - if (MLAS_CPUIDINFO::GetCPUIDInfo().HasArmNeonDot()) { - d.SQ4BitGemmKernel_CompInt8 = sqnbitgemm_neon::SQ4BitGemmKernel_CompInt8; - } - d.QuantizeARow_CompInt8 = sqnbitgemm_neon::QuantizeARow_CompInt8; + d.Q4BitGemmPerGemmWorkspaceSize = sqnbitgemm_neon::Q4BitGemmPerGemmWorkspaceSize; + d.Q4BitGemmPerGemmWorkspaceAlignment = sqnbitgemm_neon::Q4BitGemmPerGemmWorkspaceAlignment; + + d.SQ4BitGemmM1Kernel_CompFp32 = sqnbitgemm_neon::SQ4BitGemmM1Kernel_CompFp32; + d.SQ4BitBlkDequantBForSgemm_CompFp32 = sqnbitgemm_neon::SQ4BitBlkDequantBForSgemm_CompFp32; + + if (InitializeWithDotSupport) { + d.SQ4BitGemmKernel_CompInt8 = sqnbitgemm_neon::SQ4BitGemmKernel_CompInt8; + d.QuantizeARow_CompInt8 = sqnbitgemm_neon::QuantizeARow_CompInt8; + d.UsePacked_CompInt8 = sqnbitgemm_neon::UsePacked_CompInt8; + +#ifdef USE_KLEIDIAI + d.SQ4BitGemmKernel_Packed_CompInt8 = sqnbitgemm_neon::SQ4BitGemmKernel_Packed_CompInt8; + d.QuantizeA_Packed_CompInt8 = sqnbitgemm_neon::QuantizeA_Packed_CompInt8; +#endif + } #if defined(MLAS_F16VEC_INTRINSICS_SUPPORTED) && defined(MLAS_TARGET_ARM64) - d.HQ4BitGemmPackQuantBData = sqnbitgemm_neon::HQ4BitGemmPackQuantBData_CompFp16; - d.HQ4BitBlkDequantBForHgemm_CompFp16 = sqnbitgemm_neon::HQ4BitBlkDequantBForHgemm_CompFp16; - d.HQ4BitGemmKernel_CompFp16 = sqnbitgemm_neon::HQ4BitGemmKernel_CompFp16; + d.HQ4BitGemmPackQuantBData = sqnbitgemm_neon::HQ4BitGemmPackQuantBData_CompFp16; + d.HQ4BitBlkDequantBForHgemm_CompFp16 = sqnbitgemm_neon::HQ4BitBlkDequantBForHgemm_CompFp16; + d.HQ4BitGemmKernel_CompFp16 = sqnbitgemm_neon::HQ4BitGemmKernel_CompFp16; #endif // MLAS_F16VEC_INTRINSICS_SUPPORTED && MLAS_TARGET_ARM64 - return d; -}(); + return d; + }(); + + return MlasQNBitGemmDispatchNeon; +} diff --git a/onnxruntime/core/mlas/lib/qnbitgemm_kernel_neon.h b/onnxruntime/core/mlas/lib/qnbitgemm_kernel_neon.h index ccadd24ac1991..a254ec9f92596 100644 --- a/onnxruntime/core/mlas/lib/qnbitgemm_kernel_neon.h +++ b/onnxruntime/core/mlas/lib/qnbitgemm_kernel_neon.h @@ -23,6 +23,7 @@ Module Name: #include #include +#include "mlas_qnbit.h" #include "mlasi.h" namespace sqnbitgemm_neon @@ -107,6 +108,13 @@ HQ4BitGemmKernel_CompFp16( // SQNBIT_CompInt8 declarations +bool +UsePacked_CompInt8( + size_t K, + size_t BlkLen, + bool HasZp +); + void QuantizeARow_CompInt8( size_t BlkLen, @@ -131,6 +139,35 @@ SQ4BitGemmKernel_CompInt8( const float* Bias ); +#ifdef USE_KLEIDIAI +void +QuantizeA_Packed_CompInt8( + size_t BlkLen, + const float* A, + size_t CountM, + size_t CountK, + std::byte* QuantA +); + +void +SQ4BitGemmKernel_Packed_CompInt8( + size_t BlkLen, + const std::byte* QuantA, + const std::byte* PackedQuantBData, + float* C, + const size_t RangeStartM, + const size_t RangeCountM, + const size_t RangeStartN, + const size_t RangeCountN, + size_t CountK, + size_t ldc, + const float *Bias +); +#endif + +bool +UseKleidiAI(size_t K, size_t BlkLen, bool HasZp); + // // General helpers. // diff --git a/onnxruntime/core/mlas/lib/rotary_embedding_kernel_avx2.cpp b/onnxruntime/core/mlas/lib/rotary_embedding_kernel_avx2.cpp index 7b6c49720853a..024e67d14a0d7 100644 --- a/onnxruntime/core/mlas/lib/rotary_embedding_kernel_avx2.cpp +++ b/onnxruntime/core/mlas/lib/rotary_embedding_kernel_avx2.cpp @@ -14,14 +14,295 @@ Module Name: --*/ + +#include + #include "rotary_embedding.h" #include "rotary_embedding_kernel_avx2.h" +namespace rope_avx2 { + +namespace { + +typedef __m256 float32x8_t; +static constexpr int32_t mask_buffer[16] = {-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0}; + +template +void +RopeKernel_Avx2_fp16_Impl( + const MLAS_FP16* input, + const MLAS_FP16* sin_data, + const MLAS_FP16* cos_data, + size_t dim, + MLAS_FP16* output +); + +float32x8_t +load_fp16_and_convert_to_fp32(const MLAS_FP16* input) +{ + __m128i fp16 = _mm_lddqu_si128(reinterpret_cast(input)); + return _mm256_cvtph_ps(fp16); +} + +void +convert_to_fp16_and_store(MLAS_FP16* dst_fp16, const __m256 output) +{ + __m128i fp16_chunk = _mm256_cvtps_ph(output, _MM_FROUND_TO_NEAREST_INT); + _mm_storeu_si128(reinterpret_cast<__m128i*>(dst_fp16), fp16_chunk); +} + +template <> +void +RopeKernel_Avx2_fp16_Impl( + const MLAS_FP16* input, + const MLAS_FP16* sin_data, + const MLAS_FP16* cos_data, + size_t dim, + MLAS_FP16* output +) +{ + // ?cast input -> const unsigned short* + const size_t half_dim = dim >> 1; + size_t i = 0, j = half_dim; + for (; i + 7 < half_dim; i += 8, j += 8) { + float32x8_t real = load_fp16_and_convert_to_fp32(input + i); + float32x8_t imag = load_fp16_and_convert_to_fp32(input + j); + float32x8_t sin_val = load_fp16_and_convert_to_fp32(sin_data + i); + float32x8_t cos_val = load_fp16_and_convert_to_fp32(cos_data + i); + // Compute Real and Imaginary output values + float32x8_t real_out = _mm256_fmsub_ps(real, cos_val, _mm256_mul_ps(imag, sin_val)); + float32x8_t imag_out = _mm256_fmadd_ps(real, sin_val, _mm256_mul_ps(imag, cos_val)); + // Store back into non interleaved format + convert_to_fp16_and_store(output + i, real_out); + convert_to_fp16_and_store(output + j, imag_out); + } + for (; i < half_dim; i++, j++) { + float real = input[i].ToFloat(); + float imag = input[j].ToFloat(); + float sin_val = sin_data[i]; + float cos_val = cos_data[i]; + output[i] = MLAS_FP16(real * cos_val - imag * sin_val); + output[j] = MLAS_FP16(real * sin_val + imag * cos_val); + } +} + +template <> +void +RopeKernel_Avx2_fp16_Impl( + const MLAS_FP16* input, + const MLAS_FP16* sin_data, + const MLAS_FP16* cos_data, + size_t dim, + MLAS_FP16* output +) +{ + // ?cast input -> const unsigned short* + size_t i = 0; + for (; i + 15 < dim; i += 16) { + float32x8_t x0 = load_fp16_and_convert_to_fp32(input + i); + float32x8_t x1 = load_fp16_and_convert_to_fp32(input + i + 8); + float32x8_t real_s = _mm256_shuffle_ps(x0, x1, 0b10001000); + float32x8_t imag_s = _mm256_shuffle_ps(x0, x1, 0b11011101); + __m256i in_mask_vec = _mm256_set_epi32(7, 6, 3, 2, 5, 4, 1, 0); + float32x8_t real = _mm256_permutevar8x32_ps(real_s, in_mask_vec); + float32x8_t imag = _mm256_permutevar8x32_ps(imag_s, in_mask_vec); + float32x8_t sin_val = load_fp16_and_convert_to_fp32(sin_data + i / 2); + float32x8_t cos_val = load_fp16_and_convert_to_fp32(cos_data + i / 2); + // Compute Real and Imaginary output values + float32x8_t real_out = _mm256_fmsub_ps(real, cos_val, _mm256_mul_ps(imag, sin_val)); + float32x8_t imag_out = _mm256_fmadd_ps(real, sin_val, _mm256_mul_ps(imag, cos_val)); + // Store back into interleaved format + __m256i out_mask_vec = _mm256_set_epi32(7, 6, 3, 2, 5, 4, 1, 0); + float32x8_t real_out_s = _mm256_permutevar8x32_ps(real_out, out_mask_vec); + float32x8_t imag_out_s = _mm256_permutevar8x32_ps(imag_out, out_mask_vec); + float32x8_t y0 = _mm256_unpacklo_ps(real_out_s, imag_out_s); + float32x8_t y1 = _mm256_unpackhi_ps(real_out_s, imag_out_s); + + // Store back into non interleaved format + convert_to_fp16_and_store(output + i, y0); + convert_to_fp16_and_store(output + i + 8, y1); + } + + for (; i < dim; i++) { + size_t cache_idx = i / 2; + bool sign = i & 1; + size_t j = sign ? i - 1 : i + 1; + + float output_data_i = input[i].ToFloat() * cos_data[cache_idx].ToFloat(); + float input_data_j = input[j].ToFloat(); + float sin_data_cache_idx = sin_data[cache_idx].ToFloat(); + if (sign) { + output_data_i += input_data_j * sin_data_cache_idx; + } else { + output_data_i -= input_data_j * sin_data_cache_idx; + } + output[i] = MLAS_FP16(output_data_i); + } +} + +template +void +RopeKernel_Avx2_fp32_Impl( + const float* input, + const float* sin_data, + const float* cos_data, + size_t dim, + float* output +); + +template <> +void +RopeKernel_Avx2_fp32_Impl( + const float* input, + const float* sin_data, + const float* cos_data, + size_t dim, + float* output +) { + const size_t half_dim = dim >> 1; + size_t i = 0, j = half_dim; + for (; i + 7 < half_dim; i += 8, j += 8) { + float32x8_t real = _mm256_loadu_ps(input + i); + float32x8_t imag = _mm256_loadu_ps(input + j); + float32x8_t sin_val = _mm256_loadu_ps(sin_data + i); + float32x8_t cos_val = _mm256_loadu_ps(cos_data + i); + //Compute Real and Imaginary output values + float32x8_t real_out = _mm256_fmsub_ps(real, cos_val, _mm256_mul_ps(imag, sin_val)); + float32x8_t imag_out = _mm256_fmadd_ps(real, sin_val, _mm256_mul_ps(imag, cos_val)); + //Store back into non interleaved format + _mm256_storeu_ps(output + i, real_out); + _mm256_storeu_ps(output + j, imag_out); + } + if (half_dim - i != 0) { + size_t rem = half_dim - i; + const __m256i mask = _mm256_loadu_si256((const __m256i*)(mask_buffer + 8 - rem)); + //Use a mask to load the remaining input values + float32x8_t real = _mm256_maskload_ps(input + i, mask); + float32x8_t imag = _mm256_maskload_ps(input + j, mask); + float32x8_t sin_val = _mm256_maskload_ps(sin_data + i, mask); + float32x8_t cos_val = _mm256_maskload_ps(cos_data + i, mask); + //Compute Real and Imaginary output values + float32x8_t real_out = _mm256_fmsub_ps(real, cos_val, _mm256_mul_ps(imag, sin_val)); + float32x8_t imag_out = _mm256_fmadd_ps(real, sin_val, _mm256_mul_ps(imag, cos_val)); + //Store back into non interleaved format + _mm256_maskstore_ps(output + i, mask, real_out); + _mm256_maskstore_ps(output + j, mask, imag_out); + } +} + +template <> +void +RopeKernel_Avx2_fp32_Impl( + const float* input, + const float* sin_data, + const float* cos_data, + size_t dim, + float* output +) { + size_t i = 0; + for (; i + 15 < dim; i += 16) { + float32x8_t x0 = _mm256_loadu_ps(input + i); + float32x8_t x1 = _mm256_loadu_ps(input + i + 8); + //Load imaginary and real values to separate non-interleaved vectors + float32x8_t real_s = _mm256_shuffle_ps(x0, x1, 0b10001000); + float32x8_t imag_s = _mm256_shuffle_ps(x0, x1, 0b11011101); + __m256i in_mask_vec = _mm256_set_epi32(7, 6, 3, 2, 5, 4, 1, 0); + float32x8_t real = _mm256_permutevar8x32_ps(real_s, in_mask_vec); + float32x8_t imag = _mm256_permutevar8x32_ps(imag_s, in_mask_vec); + float32x8_t sin_val = _mm256_loadu_ps(sin_data + i / 2); + float32x8_t cos_val = _mm256_loadu_ps(cos_data + i / 2); + //Compute Real and Imaginary output values + float32x8_t real_out = _mm256_fmsub_ps(real, cos_val, _mm256_mul_ps(imag, sin_val)); + float32x8_t imag_out = _mm256_fmadd_ps(real, sin_val, _mm256_mul_ps(imag, cos_val)); + //Store back into interleaved format + __m256i out_mask_vec = _mm256_set_epi32(7, 6, 3, 2, 5, 4, 1, 0); + float32x8_t real_out_s = _mm256_permutevar8x32_ps(real_out, out_mask_vec); + float32x8_t imag_out_s = _mm256_permutevar8x32_ps(imag_out, out_mask_vec); + float32x8_t y0 = _mm256_unpacklo_ps(real_out_s, imag_out_s); + float32x8_t y1 = _mm256_unpackhi_ps(real_out_s, imag_out_s); + _mm256_storeu_ps(output + i, y0); + _mm256_storeu_ps(output + i + 8, y1); + } + if (dim - i != 0) { + size_t rem = dim - i; + const __m256i mask0 = _mm256_loadu_si256((const __m256i*)(mask_buffer + 8 - (rem>8?8:rem))); + const __m256i mask1 = _mm256_loadu_si256((const __m256i*)(mask_buffer + 8 - (rem>8?(rem-8):0))); + float32x8_t x0 = _mm256_maskload_ps(input + i, mask0); //Load the first set of data using mask + float32x8_t x1 = _mm256_maskload_ps(input + i + 8, mask1); //Load the reminder of data using a second mask + //Load imaginary and real values to separate non-interleaved vectors + float32x8_t real_s = _mm256_shuffle_ps(x0, x1, 0b10001000); + float32x8_t imag_s = _mm256_shuffle_ps(x0, x1, 0b11011101); + __m256i in_mask_vec = _mm256_set_epi32(7, 6, 3, 2, 5, 4, 1, 0); + float32x8_t real = _mm256_permutevar8x32_ps(real_s, in_mask_vec); + float32x8_t imag = _mm256_permutevar8x32_ps(imag_s, in_mask_vec); + float32x8_t sin_val = _mm256_loadu_ps(sin_data+ i / 2); + float32x8_t cos_val = _mm256_loadu_ps(cos_data + i / 2); + //Compute Real and Imaginary output values + float32x8_t real_out = _mm256_fmsub_ps(real, cos_val, _mm256_mul_ps(imag, sin_val)); + float32x8_t imag_out = _mm256_fmadd_ps(real, sin_val, _mm256_mul_ps(imag, cos_val)); + //Store back into interleaved format + __m256i out_mask_vec = _mm256_set_epi32(7, 6, 3, 2, 5, 4, 1, 0); + float32x8_t real_out_s = _mm256_permutevar8x32_ps(real_out, out_mask_vec); + float32x8_t imag_out_s = _mm256_permutevar8x32_ps(imag_out, out_mask_vec); + float32x8_t y0 = _mm256_unpacklo_ps(real_out_s, imag_out_s); + float32x8_t y1 = _mm256_unpackhi_ps(real_out_s, imag_out_s); + _mm256_maskstore_ps(output + i, mask0, y0); + _mm256_maskstore_ps(output + i + 8, mask1, y1); + } +} + +} // rope_avx2 namespace + +void +RopeKernel_Avx2_fp32( + const float* input, + const float* sin_data, + const float* cos_data, + size_t dim, + bool interleaved, + float* output +) { + // real part and imaginary part must be paired + assert(dim % 2 == 0); + const auto* input_impl = reinterpret_cast(input); + const auto* sin_impl = reinterpret_cast(sin_data); + const auto* cos_impl = reinterpret_cast(cos_data); + auto* output_impl = reinterpret_cast(output); + + if (interleaved) { + RopeKernel_Avx2_fp32_Impl(input_impl, sin_impl, cos_impl, dim, output_impl); + } else { + RopeKernel_Avx2_fp32_Impl(input_impl, sin_impl, cos_impl, dim, output_impl); + } +} + +void +RopeKernel_Avx2_fp16( + const MLAS_FP16* input, + const MLAS_FP16* sin_data, + const MLAS_FP16* cos_data, + size_t dim, + bool interleaved, + MLAS_FP16* output +) +{ + // real part and imaginary part must be paired + assert(dim % 2 == 0); + + if (interleaved) { + RopeKernel_Avx2_fp16_Impl(input, sin_data, cos_data, dim, output); + } else { + RopeKernel_Avx2_fp16_Impl(input, sin_data, cos_data, dim, output); + } +} +} + // // Kernel dispatch structure definition. // const MLAS_ROPE_DISPATCH MlasRopeDispatchAvx2 = []() { MLAS_ROPE_DISPATCH d; - d.SRope = rope_avx2::RopeKernel_Avx2; + d.SRope = rope_avx2::RopeKernel_Avx2_fp32; + d.HRope = rope_avx2::RopeKernel_Avx2_fp16; return d; }(); diff --git a/onnxruntime/core/mlas/lib/rotary_embedding_kernel_avx2.h b/onnxruntime/core/mlas/lib/rotary_embedding_kernel_avx2.h index 18a2e11998644..c08833e114b9e 100644 --- a/onnxruntime/core/mlas/lib/rotary_embedding_kernel_avx2.h +++ b/onnxruntime/core/mlas/lib/rotary_embedding_kernel_avx2.h @@ -34,4 +34,14 @@ RopeKernel_Avx2( float* output ); +void +RopeKernel_Avx2_fp16( + const MLAS_FP16* input, + const MLAS_FP16* sin_data, + const MLAS_FP16* cos_data, + size_t dim, + bool interleaved, + MLAS_FP16* output +); + } // namespace rope_avx2 diff --git a/onnxruntime/core/mlas/lib/rotary_embedding_kernel_avx2_fp32.cpp b/onnxruntime/core/mlas/lib/rotary_embedding_kernel_avx2_fp32.cpp deleted file mode 100644 index 7124b82606978..0000000000000 --- a/onnxruntime/core/mlas/lib/rotary_embedding_kernel_avx2_fp32.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - -Licensed under the MIT License. - -Module Name: - - rotary_embedding_kernel_avx2_fp32.cpp - -Abstract: - - This module implements the fp32 rotary embedding kernels using AVX2. - ---*/ - -#include - -#include "rotary_embedding.h" -#include "rotary_embedding_kernel_avx2.h" - -namespace rope_avx2 { - -namespace { - -typedef __m256 float32x8_t; - -template -void -RopeKernel_Avx2_Impl( - const float* input, - const float* sin_data, - const float* cos_data, - size_t dim, - float* output -); - -template <> -void -RopeKernel_Avx2_Impl( - const float* input, - const float* sin_data, - const float* cos_data, - size_t dim, - float* output -) { - const size_t half_dim = dim >> 1; - size_t i = 0, j = half_dim; - for (; i + 7 < half_dim; i += 8, j += 8) { - float32x8_t real = _mm256_loadu_ps(input + i); - float32x8_t imag = _mm256_loadu_ps(input + j); - float32x8_t sin_val = _mm256_loadu_ps(sin_data + i); - float32x8_t cos_val = _mm256_loadu_ps(cos_data + i); - //Compute Real and Imaginary output values - float32x8_t real_out = _mm256_fmsub_ps(real, cos_val, _mm256_mul_ps(imag, sin_val)); - float32x8_t imag_out = _mm256_fmadd_ps(real, sin_val, _mm256_mul_ps(imag, cos_val)); - //Store back into non interleaved format - _mm256_storeu_ps(output + i, real_out); - _mm256_storeu_ps(output + j, imag_out); - } - if (half_dim - i != 0) { - size_t rem = half_dim - i; - static constexpr int32_t mask_buffer[16] = {-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0}; - const __m256i mask = _mm256_loadu_si256((const __m256i*)(mask_buffer + 8 - rem)); - //Use a mask to load the remaining input values - float32x8_t real = _mm256_maskload_ps(input + i, mask); - float32x8_t imag = _mm256_maskload_ps(input + j, mask); - float32x8_t sin_val = _mm256_maskload_ps(sin_data + i, mask); - float32x8_t cos_val = _mm256_maskload_ps(cos_data + i, mask); - //Compute Real and Imaginary output values - float32x8_t real_out = _mm256_fmsub_ps(real, cos_val, _mm256_mul_ps(imag, sin_val)); - float32x8_t imag_out = _mm256_fmadd_ps(real, sin_val, _mm256_mul_ps(imag, cos_val)); - //Store back into non interleaved format - _mm256_maskstore_ps(output + i, mask, real_out); - _mm256_maskstore_ps(output + j, mask, imag_out); - } -} - -template <> -void -RopeKernel_Avx2_Impl( - const float* input, - const float* sin_data, - const float* cos_data, - size_t dim, - float* output -) { - size_t i = 0; - for (; i + 15 < dim; i += 16) { - float32x8_t x0 = _mm256_loadu_ps(input + i); - float32x8_t x1 = _mm256_loadu_ps(input + i + 8); - //Load imaginary and real values to separate non-interleaved vectors - float32x8_t real_s = _mm256_shuffle_ps(x0, x1, 0b10001000); - float32x8_t imag_s = _mm256_shuffle_ps(x0, x1, 0b11011101); - __m256i in_mask_vec = _mm256_set_epi32(7, 6, 3, 2, 5, 4, 1, 0); - float32x8_t real = _mm256_permutevar8x32_ps(real_s, in_mask_vec); - float32x8_t imag = _mm256_permutevar8x32_ps(imag_s, in_mask_vec); - float32x8_t sin_val = _mm256_loadu_ps(sin_data + i / 2); - float32x8_t cos_val = _mm256_loadu_ps(cos_data + i / 2); - //Compute Real and Imaginary output values - float32x8_t real_out = _mm256_fmsub_ps(real, cos_val, _mm256_mul_ps(imag, sin_val)); - float32x8_t imag_out = _mm256_fmadd_ps(real, sin_val, _mm256_mul_ps(imag, cos_val)); - //Store back into interleaved format - __m256i out_mask_vec = _mm256_set_epi32(7, 6, 3, 2, 5, 4, 1, 0); - float32x8_t real_out_s = _mm256_permutevar8x32_ps(real_out, out_mask_vec); - float32x8_t imag_out_s = _mm256_permutevar8x32_ps(imag_out, out_mask_vec); - float32x8_t y0 = _mm256_unpacklo_ps(real_out_s, imag_out_s); - float32x8_t y1 = _mm256_unpackhi_ps(real_out_s, imag_out_s); - _mm256_storeu_ps(output + i, y0); - _mm256_storeu_ps(output + i + 8, y1); - } - if (dim - i != 0) { - size_t rem = dim - i; - static constexpr int32_t mask_buffer[16] = {-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0}; - const __m256i mask0 = _mm256_loadu_si256((const __m256i*)(mask_buffer + 8 - (rem>8?8:rem))); - const __m256i mask1 = _mm256_loadu_si256((const __m256i*)(mask_buffer + 8 - (rem>8?(rem-8):0))); - float32x8_t x0 = _mm256_maskload_ps(input + i, mask0); //Load the first set of data using mask - float32x8_t x1 = _mm256_maskload_ps(input + i + 8, mask1); //Load the reminder of data using a second mask - //Load imaginary and real values to separate non-interleaved vectors - float32x8_t real_s = _mm256_shuffle_ps(x0, x1, 0b10001000); - float32x8_t imag_s = _mm256_shuffle_ps(x0, x1, 0b11011101); - __m256i in_mask_vec = _mm256_set_epi32(7, 6, 3, 2, 5, 4, 1, 0); - float32x8_t real = _mm256_permutevar8x32_ps(real_s, in_mask_vec); - float32x8_t imag = _mm256_permutevar8x32_ps(imag_s, in_mask_vec); - float32x8_t sin_val = _mm256_loadu_ps(sin_data+ i / 2); - float32x8_t cos_val = _mm256_loadu_ps(cos_data + i / 2); - //Compute Real and Imaginary output values - float32x8_t real_out = _mm256_fmsub_ps(real, cos_val, _mm256_mul_ps(imag, sin_val)); - float32x8_t imag_out = _mm256_fmadd_ps(real, sin_val, _mm256_mul_ps(imag, cos_val)); - //Store back into interleaved format - __m256i out_mask_vec = _mm256_set_epi32(7, 6, 3, 2, 5, 4, 1, 0); - float32x8_t real_out_s = _mm256_permutevar8x32_ps(real_out, out_mask_vec); - float32x8_t imag_out_s = _mm256_permutevar8x32_ps(imag_out, out_mask_vec); - float32x8_t y0 = _mm256_unpacklo_ps(real_out_s, imag_out_s); - float32x8_t y1 = _mm256_unpackhi_ps(real_out_s, imag_out_s); - _mm256_maskstore_ps(output + i, mask0, y0); - _mm256_maskstore_ps(output + i + 8, mask1, y1); - } -} - -} // namespace - -void -RopeKernel_Avx2( - const float* input, - const float* sin_data, - const float* cos_data, - size_t dim, - bool interleaved, - float* output -) { - // real part and imaginary part must be paired - assert(dim % 2 == 0); - const auto* input_impl = reinterpret_cast(input); - const auto* sin_impl = reinterpret_cast(sin_data); - const auto* cos_impl = reinterpret_cast(cos_data); - auto* output_impl = reinterpret_cast(output); - - if (interleaved) { - RopeKernel_Avx2_Impl(input_impl, sin_impl, cos_impl, dim, output_impl); - } else { - RopeKernel_Avx2_Impl(input_impl, sin_impl, cos_impl, dim, output_impl); - } -} - -} diff --git a/onnxruntime/core/mlas/lib/sgemm.cpp b/onnxruntime/core/mlas/lib/sgemm.cpp index f8b25fb42caf3..616622a8c1f53 100644 --- a/onnxruntime/core/mlas/lib/sgemm.cpp +++ b/onnxruntime/core/mlas/lib/sgemm.cpp @@ -1580,14 +1580,7 @@ MlasGemmBatch( const double Complexity = double(M) * double(N) * double(K); - ptrdiff_t TargetThreadCount; - - if (Complexity < double(MLAS_SGEMM_THREAD_COMPLEXITY * GetMlasPlatform().MaximumThreadCount)) { - TargetThreadCount = ptrdiff_t(Complexity / double(MLAS_SGEMM_THREAD_COMPLEXITY)) + 1; - } else { - TargetThreadCount = GetMlasPlatform().MaximumThreadCount; - } - + ptrdiff_t TargetThreadCount = ptrdiff_t(Complexity / double(MLAS_SGEMM_THREAD_COMPLEXITY)) + 1; ptrdiff_t MaximumThreadCount = MlasGetMaximumThreadCount(ThreadPool); if (TargetThreadCount >= MaximumThreadCount) { diff --git a/onnxruntime/core/mlas/lib/softmax_kernel_neon_fp16.cpp b/onnxruntime/core/mlas/lib/softmax_kernel_neon_fp16.cpp index b4e88111b3c58..dfd65d9d55fbb 100644 --- a/onnxruntime/core/mlas/lib/softmax_kernel_neon_fp16.cpp +++ b/onnxruntime/core/mlas/lib/softmax_kernel_neon_fp16.cpp @@ -20,7 +20,6 @@ Module Name: #include "softmax.h" #include "softmax_kernel_neon.h" -// TODO(fajin): intra-loop parallelism namespace softmax_neon { template @@ -44,7 +43,7 @@ struct MlasExpConstants { T MaximumExponent; }; -const MlasExpConstants<_mlas_fp16_> ExpConstantsFp16 = { +constexpr MlasExpConstants<_mlas_fp16_> ExpConstantsFp16 = { 0xcc55, // -25 * ln2 0x498c, // 16 * ln2 0xc95f, // -15.5 * ln2 @@ -64,59 +63,57 @@ const MlasExpConstants<_mlas_fp16_> ExpConstantsFp16 = { 0x3C00, // 15 }; -const MlasExpConstants ExpConstantsFp16x8 = { - MlasBroadcastFloat16x8(ExpConstantsFp16.LowerRange), - MlasBroadcastFloat16x8(ExpConstantsFp16.UpperRange), - MlasBroadcastFloat16x8(ExpConstantsFp16.LowerRangeSumExp), - MlasBroadcastFloat16x8(ExpConstantsFp16.UpperRangeSumExp), - MlasBroadcastFloat16x8(ExpConstantsFp16.RoundingBias), - MlasBroadcastFloat16x8(ExpConstantsFp16.Log2Reciprocal), - MlasBroadcastFloat16x8(ExpConstantsFp16.Log2High), - MlasBroadcastFloat16x8(ExpConstantsFp16.Log2Mid), - MlasBroadcastFloat16x8(ExpConstantsFp16.Log2Low), - MlasBroadcastFloat16x8(ExpConstantsFp16.poly_0), - MlasBroadcastFloat16x8(ExpConstantsFp16.poly_1), - MlasBroadcastFloat16x8(ExpConstantsFp16.poly_2), - MlasBroadcastFloat16x8(ExpConstantsFp16.poly_3), - MlasBroadcastFloat16x8(ExpConstantsFp16.poly_4), - MlasBroadcastFloat16x8(ExpConstantsFp16.poly_56), - MlasBroadcastFloat16x8(ExpConstantsFp16.MinimumExponent), - MlasBroadcastFloat16x8(ExpConstantsFp16.MaximumExponent), -}; - -const MlasExpConstants ExpConstantsFp16x4 = { - MlasBroadcastFloat16x4(ExpConstantsFp16.LowerRange), - MlasBroadcastFloat16x4(ExpConstantsFp16.UpperRange), - MlasBroadcastFloat16x4(ExpConstantsFp16.LowerRangeSumExp), - MlasBroadcastFloat16x4(ExpConstantsFp16.UpperRangeSumExp), - MlasBroadcastFloat16x4(ExpConstantsFp16.RoundingBias), - MlasBroadcastFloat16x4(ExpConstantsFp16.Log2Reciprocal), - MlasBroadcastFloat16x4(ExpConstantsFp16.Log2High), - MlasBroadcastFloat16x4(ExpConstantsFp16.Log2Mid), - MlasBroadcastFloat16x4(ExpConstantsFp16.Log2Low), - MlasBroadcastFloat16x4(ExpConstantsFp16.poly_0), - MlasBroadcastFloat16x4(ExpConstantsFp16.poly_1), - MlasBroadcastFloat16x4(ExpConstantsFp16.poly_2), - MlasBroadcastFloat16x4(ExpConstantsFp16.poly_3), - MlasBroadcastFloat16x4(ExpConstantsFp16.poly_4), - MlasBroadcastFloat16x4(ExpConstantsFp16.poly_56), - MlasBroadcastFloat16x4(ExpConstantsFp16.MinimumExponent), - MlasBroadcastFloat16x4(ExpConstantsFp16.MaximumExponent), -}; - template MLAS_FORCEINLINE -MlasExpConstants Get_Exp_Constants(); +const MlasExpConstants& Get_Exp_Constants(); template <> MLAS_FORCEINLINE -MlasExpConstants Get_Exp_Constants() { +const MlasExpConstants& Get_Exp_Constants() { + const static MlasExpConstants ExpConstantsFp16x8 = { + MlasBroadcastFloat16x8(ExpConstantsFp16.LowerRange), + MlasBroadcastFloat16x8(ExpConstantsFp16.UpperRange), + MlasBroadcastFloat16x8(ExpConstantsFp16.LowerRangeSumExp), + MlasBroadcastFloat16x8(ExpConstantsFp16.UpperRangeSumExp), + MlasBroadcastFloat16x8(ExpConstantsFp16.RoundingBias), + MlasBroadcastFloat16x8(ExpConstantsFp16.Log2Reciprocal), + MlasBroadcastFloat16x8(ExpConstantsFp16.Log2High), + MlasBroadcastFloat16x8(ExpConstantsFp16.Log2Mid), + MlasBroadcastFloat16x8(ExpConstantsFp16.Log2Low), + MlasBroadcastFloat16x8(ExpConstantsFp16.poly_0), + MlasBroadcastFloat16x8(ExpConstantsFp16.poly_1), + MlasBroadcastFloat16x8(ExpConstantsFp16.poly_2), + MlasBroadcastFloat16x8(ExpConstantsFp16.poly_3), + MlasBroadcastFloat16x8(ExpConstantsFp16.poly_4), + MlasBroadcastFloat16x8(ExpConstantsFp16.poly_56), + MlasBroadcastFloat16x8(ExpConstantsFp16.MinimumExponent), + MlasBroadcastFloat16x8(ExpConstantsFp16.MaximumExponent), + }; return ExpConstantsFp16x8; } template <> MLAS_FORCEINLINE -MlasExpConstants Get_Exp_Constants() { +const MlasExpConstants& Get_Exp_Constants() { + const static MlasExpConstants ExpConstantsFp16x4 = { + MlasBroadcastFloat16x4(ExpConstantsFp16.LowerRange), + MlasBroadcastFloat16x4(ExpConstantsFp16.UpperRange), + MlasBroadcastFloat16x4(ExpConstantsFp16.LowerRangeSumExp), + MlasBroadcastFloat16x4(ExpConstantsFp16.UpperRangeSumExp), + MlasBroadcastFloat16x4(ExpConstantsFp16.RoundingBias), + MlasBroadcastFloat16x4(ExpConstantsFp16.Log2Reciprocal), + MlasBroadcastFloat16x4(ExpConstantsFp16.Log2High), + MlasBroadcastFloat16x4(ExpConstantsFp16.Log2Mid), + MlasBroadcastFloat16x4(ExpConstantsFp16.Log2Low), + MlasBroadcastFloat16x4(ExpConstantsFp16.poly_0), + MlasBroadcastFloat16x4(ExpConstantsFp16.poly_1), + MlasBroadcastFloat16x4(ExpConstantsFp16.poly_2), + MlasBroadcastFloat16x4(ExpConstantsFp16.poly_3), + MlasBroadcastFloat16x4(ExpConstantsFp16.poly_4), + MlasBroadcastFloat16x4(ExpConstantsFp16.poly_56), + MlasBroadcastFloat16x4(ExpConstantsFp16.MinimumExponent), + MlasBroadcastFloat16x4(ExpConstantsFp16.MaximumExponent), + }; return ExpConstantsFp16x4; } @@ -124,7 +121,7 @@ MlasExpConstants Get_Exp_Constants() { template MLAS_FORCEINLINE T Exp_Vector_Fp16(T x) { - const auto constants = Get_Exp_Constants(); + const auto& constants = Get_Exp_Constants(); auto clamped_x = MlasClampFloat16(x, constants.LowerRange, constants.UpperRange); // integral @@ -242,7 +239,7 @@ void Exp_Kernel_Fp16(const MLAS_FP16* Input, MLAS_FP16* Output, size_t N) { template MLAS_FORCEINLINE T SumExp_Vector_Fp16(T x, T negative_maximum) { - const auto constants = Get_Exp_Constants(); + const auto& constants = Get_Exp_Constants(); auto clamped_x = MlasMaximumFloat16(MlasAddFloat16(x, negative_maximum), constants.LowerRangeSumExp); // integral @@ -419,7 +416,7 @@ struct MlasTanhConstants { T beta_0; }; -const MlasTanhConstants<_mlas_fp16_> TanhConstantsFp16 = { +constexpr MlasTanhConstants<_mlas_fp16_> TanhConstantsFp16 = { 0xc308, // -3.51562 0x4308, // 3.51562 0x0001, @@ -432,45 +429,43 @@ const MlasTanhConstants<_mlas_fp16_> TanhConstantsFp16 = { 0x1d03, }; -const MlasTanhConstants TanhConstantsFp16x8 = { - MlasBroadcastFloat16x8(TanhConstantsFp16.LowerRange), - MlasBroadcastFloat16x8(TanhConstantsFp16.UpperRange), - MlasBroadcastFloat16x8(TanhConstantsFp16.alpha_7), - MlasBroadcastFloat16x8(TanhConstantsFp16.alpha_5), - MlasBroadcastFloat16x8(TanhConstantsFp16.alpha_3), - MlasBroadcastFloat16x8(TanhConstantsFp16.alpha_1), - MlasBroadcastFloat16x8(TanhConstantsFp16.beta_6), - MlasBroadcastFloat16x8(TanhConstantsFp16.beta_4), - MlasBroadcastFloat16x8(TanhConstantsFp16.beta_2), - MlasBroadcastFloat16x8(TanhConstantsFp16.beta_0), -}; - -const MlasTanhConstants TanhConstantsFp16x4 = { - MlasBroadcastFloat16x4(TanhConstantsFp16.LowerRange), - MlasBroadcastFloat16x4(TanhConstantsFp16.UpperRange), - MlasBroadcastFloat16x4(TanhConstantsFp16.alpha_7), - MlasBroadcastFloat16x4(TanhConstantsFp16.alpha_5), - MlasBroadcastFloat16x4(TanhConstantsFp16.alpha_3), - MlasBroadcastFloat16x4(TanhConstantsFp16.alpha_1), - MlasBroadcastFloat16x4(TanhConstantsFp16.beta_6), - MlasBroadcastFloat16x4(TanhConstantsFp16.beta_4), - MlasBroadcastFloat16x4(TanhConstantsFp16.beta_2), - MlasBroadcastFloat16x4(TanhConstantsFp16.beta_0), -}; - template MLAS_FORCEINLINE -MlasTanhConstants Get_Tanh_Constants(); +const MlasTanhConstants& Get_Tanh_Constants(); template <> MLAS_FORCEINLINE -MlasTanhConstants Get_Tanh_Constants() { +const MlasTanhConstants& Get_Tanh_Constants() { + const static MlasTanhConstants TanhConstantsFp16x8 = { + MlasBroadcastFloat16x8(TanhConstantsFp16.LowerRange), + MlasBroadcastFloat16x8(TanhConstantsFp16.UpperRange), + MlasBroadcastFloat16x8(TanhConstantsFp16.alpha_7), + MlasBroadcastFloat16x8(TanhConstantsFp16.alpha_5), + MlasBroadcastFloat16x8(TanhConstantsFp16.alpha_3), + MlasBroadcastFloat16x8(TanhConstantsFp16.alpha_1), + MlasBroadcastFloat16x8(TanhConstantsFp16.beta_6), + MlasBroadcastFloat16x8(TanhConstantsFp16.beta_4), + MlasBroadcastFloat16x8(TanhConstantsFp16.beta_2), + MlasBroadcastFloat16x8(TanhConstantsFp16.beta_0), + }; return TanhConstantsFp16x8; } template <> MLAS_FORCEINLINE -MlasTanhConstants Get_Tanh_Constants() { +const MlasTanhConstants& Get_Tanh_Constants() { + const static MlasTanhConstants TanhConstantsFp16x4 = { + MlasBroadcastFloat16x4(TanhConstantsFp16.LowerRange), + MlasBroadcastFloat16x4(TanhConstantsFp16.UpperRange), + MlasBroadcastFloat16x4(TanhConstantsFp16.alpha_7), + MlasBroadcastFloat16x4(TanhConstantsFp16.alpha_5), + MlasBroadcastFloat16x4(TanhConstantsFp16.alpha_3), + MlasBroadcastFloat16x4(TanhConstantsFp16.alpha_1), + MlasBroadcastFloat16x4(TanhConstantsFp16.beta_6), + MlasBroadcastFloat16x4(TanhConstantsFp16.beta_4), + MlasBroadcastFloat16x4(TanhConstantsFp16.beta_2), + MlasBroadcastFloat16x4(TanhConstantsFp16.beta_0), + }; return TanhConstantsFp16x4; } @@ -478,7 +473,7 @@ MlasTanhConstants Get_Tanh_Constants() { template MLAS_FORCEINLINE T Tanh_Vector_Fp16(T x) { - const auto constants = Get_Tanh_Constants(); + const auto& constants = Get_Tanh_Constants(); x = MlasClampFloat16(x, constants.LowerRange, constants.UpperRange); T x_2 = MlasMultiplyFloat16(x, x); diff --git a/onnxruntime/core/mlas/lib/sqnbitgemm_kernel_avx2.cpp b/onnxruntime/core/mlas/lib/sqnbitgemm_kernel_avx2.cpp index 81615da46aa2e..79893eea85eca 100644 --- a/onnxruntime/core/mlas/lib/sqnbitgemm_kernel_avx2.cpp +++ b/onnxruntime/core/mlas/lib/sqnbitgemm_kernel_avx2.cpp @@ -1309,9 +1309,9 @@ SQ4BitGemmPackQuantBDataAndBlkSum( MLAS_QNBIT_GEMM_COMPUTE_TYPE ComputeType, const std::byte* QuantBDataBegin, const float* QuantBScaleBegin, - bool has_zp_input, + bool HasZeroPoint, const std::byte* QuantBZPBegin, - PackedQuantBDataStruct& packed_quant_b, + PackedQuantBDataStruct& PackedQuantB, MLAS_THREADPOOL* ThreadPool ) { @@ -1324,7 +1324,8 @@ SQ4BitGemmPackQuantBDataAndBlkSum( if (BlkLen == 32 && ComputeType == SQNBIT_CompInt8) { SubBlkLen = 64; } - PackQuantBDataAndBlkSum(N, BlockCountK, BlkLen, SubBlkLen, QuantBDataBegin, QuantBScaleBegin, has_zp_input, QuantBZPBegin, packed_quant_b, ThreadPool); + PackQuantBDataAndBlkSum(N, BlockCountK, BlkLen, SubBlkLen, QuantBDataBegin, QuantBScaleBegin, + HasZeroPoint, QuantBZPBegin, PackedQuantB, ThreadPool); } // diff --git a/onnxruntime/core/mlas/lib/sqnbitgemm_kernel_avx512.cpp b/onnxruntime/core/mlas/lib/sqnbitgemm_kernel_avx512.cpp index b4e25d4e4040a..ea06f954c854a 100644 --- a/onnxruntime/core/mlas/lib/sqnbitgemm_kernel_avx512.cpp +++ b/onnxruntime/core/mlas/lib/sqnbitgemm_kernel_avx512.cpp @@ -335,9 +335,9 @@ SQ4BitGemmPackQuantBDataAndBlkSum512( MLAS_QNBIT_GEMM_COMPUTE_TYPE ComputeType, const std::byte* QuantBDataBegin, const float* QuantBScaleBegin, - bool has_zp_input, + bool HasZeroPoint, const std::byte* QuantBZPBegin, - PackedQuantBDataStruct& packed_quant_b, + PackedQuantBDataStruct& PackedQuantB, MLAS_THREADPOOL* ThreadPool ) { @@ -349,7 +349,8 @@ SQ4BitGemmPackQuantBDataAndBlkSum512( if (ComputeType == SQNBIT_CompInt8) { SubBlkLen = 128; } - PackQuantBDataAndBlkSum(N, BlockCountK, BlkLen, SubBlkLen, QuantBDataBegin, QuantBScaleBegin, has_zp_input, QuantBZPBegin, packed_quant_b, ThreadPool); + PackQuantBDataAndBlkSum(N, BlockCountK, BlkLen, SubBlkLen, QuantBDataBegin, QuantBScaleBegin, + HasZeroPoint, QuantBZPBegin, PackedQuantB, ThreadPool); } const MLAS_QNBIT_GEMM_DISPATCH MlasSQNBitGemmDispatchAvx512 = []() { diff --git a/onnxruntime/core/mlas/lib/sqnbitgemm_kernel_avx512vnni.cpp b/onnxruntime/core/mlas/lib/sqnbitgemm_kernel_avx512vnni.cpp index a4468bb906bbc..c2fcd92be2364 100644 --- a/onnxruntime/core/mlas/lib/sqnbitgemm_kernel_avx512vnni.cpp +++ b/onnxruntime/core/mlas/lib/sqnbitgemm_kernel_avx512vnni.cpp @@ -317,9 +317,9 @@ SQ4BitGemmPackQuantBDataAndBlkSum512vnni( MLAS_QNBIT_GEMM_COMPUTE_TYPE ComputeType, const std::byte* QuantBDataBegin, const float* QuantBScaleBegin, - bool has_zp_input, + bool HasZeroPoint, const std::byte* QuantBZPBegin, - PackedQuantBDataStruct& packed_quant_b, + PackedQuantBDataStruct& PackedQuantB, MLAS_THREADPOOL* ThreadPool ) { @@ -331,7 +331,8 @@ SQ4BitGemmPackQuantBDataAndBlkSum512vnni( if (ComputeType == SQNBIT_CompInt8) { SubBlkLen = 128; } - PackQuantBDataAndBlkSum(N, BlockCountK, BlkLen, SubBlkLen, QuantBDataBegin, QuantBScaleBegin, has_zp_input, QuantBZPBegin, packed_quant_b, ThreadPool); + PackQuantBDataAndBlkSum(N, BlockCountK, BlkLen, SubBlkLen, QuantBDataBegin, QuantBScaleBegin, + HasZeroPoint, QuantBZPBegin, PackedQuantB, ThreadPool); } // diff --git a/onnxruntime/core/mlas/lib/sqnbitgemm_kernel_avx_common.h b/onnxruntime/core/mlas/lib/sqnbitgemm_kernel_avx_common.h index b0367b7fb9a15..02429a0c64f8e 100644 --- a/onnxruntime/core/mlas/lib/sqnbitgemm_kernel_avx_common.h +++ b/onnxruntime/core/mlas/lib/sqnbitgemm_kernel_avx_common.h @@ -11,6 +11,7 @@ Q4BitGemmPackQuantBDataSize( size_t N, size_t K, size_t BlkLen, + bool /* HasZeroPoint */, MLAS_QNBIT_GEMM_COMPUTE_TYPE ComputeType ) { @@ -302,22 +303,22 @@ PackQuantBDataAndBlkSum( size_t SubBlkLen, const std::byte* QuantBDataBegin, const float* QuantBScaleBegin, - bool has_zp_input, + bool HasZeroPoint, const std::byte* QuantBZPBegin, - PackedQuantBDataStruct& packed_quant_b, + PackedQuantBDataStruct& PackedQuantB, MLAS_THREADPOOL* ThreadPool ) { if (QuantBDataBegin) { - PackQuantB(QuantBDataBegin, packed_quant_b.PackedQuantBData, ThreadPool, N, BlockCountK, BlkLen, SubBlkLen); + PackQuantB(QuantBDataBegin, PackedQuantB.PackedQuantBData, ThreadPool, N, BlockCountK, BlkLen, SubBlkLen); } if (QuantBScaleBegin) { - std::copy(QuantBScaleBegin, QuantBScaleBegin + N * BlockCountK, packed_quant_b.PackedQuantBScale); + std::copy(QuantBScaleBegin, QuantBScaleBegin + N * BlockCountK, PackedQuantB.PackedQuantBScale); } - if ((QuantBScaleBegin && !has_zp_input) || QuantBZPBegin) { - ComputePackBlkSum(BlkLen, SubBlkLen, N, packed_quant_b.PackedQuantBScale, QuantBZPBegin, packed_quant_b.QuantBBlkSum, ThreadPool, BlockCountK); + if ((QuantBScaleBegin && !HasZeroPoint) || QuantBZPBegin) { + ComputePackBlkSum(BlkLen, SubBlkLen, N, PackedQuantB.PackedQuantBScale, QuantBZPBegin, PackedQuantB.QuantBBlkSum, ThreadPool, BlockCountK); } } @@ -331,6 +332,7 @@ Q4BitGemmPerGemmWorkspaceSize( size_t N, size_t K, size_t BlkLen, + bool /* HasZeroPoint */, MLAS_QNBIT_GEMM_COMPUTE_TYPE ComputeType ) { diff --git a/onnxruntime/core/mlas/lib/sqnbitgemm_kernel_neon_int8.cpp b/onnxruntime/core/mlas/lib/sqnbitgemm_kernel_neon_int8.cpp index 73beb06a3cfad..8dbd339468930 100644 --- a/onnxruntime/core/mlas/lib/sqnbitgemm_kernel_neon_int8.cpp +++ b/onnxruntime/core/mlas/lib/sqnbitgemm_kernel_neon_int8.cpp @@ -1,7 +1,6 @@ /*++ Copyright (c) Microsoft Corporation. All rights reserved. - Licensed under the MIT License. Module Name: @@ -20,11 +19,17 @@ Module Name: #include #include +#include #include "qnbitgemm.h" #include "qnbitgemm_kernel_neon.h" #include "sqnbitgemm_q8_block.h" +#ifdef USE_KLEIDIAI +#include "kai/ukernels/matmul/pack/kai_lhs_quant_pack_qai8dxp_f32.h" +#include "kai_ukernel_interface.h" +#endif + namespace sqnbitgemm_neon { @@ -126,6 +131,41 @@ QuantizeBlock( } // namespace +bool +UsePacked_CompInt8(size_t K, size_t BlkLen, bool HasZp) +{ + return UseKleidiAI(K, BlkLen, HasZp); +} + +#ifdef USE_KLEIDIAI +void +QuantizeA_Packed_CompInt8( + size_t, + const float* A, + size_t CountM, + size_t CountK, + std::byte* QuantA +) +{ + const kai_matmul_clamp_f32_qai8dxp_qsi4c32p_ukernel& ukernel = + CountM == 1? GetKleidiAIGemvUKernel() : GetKleidiAIGemmUKernel(); + + const size_t mr = ukernel.get_mr(); + const size_t kr = ukernel.get_kr(); + const size_t sr = ukernel.get_sr(); + + const size_t src_stride = CountK * sizeof(float); + const size_t lhs_offset = kai_get_lhs_offset_lhs_quant_pack_qai8dxp_f32(0, src_stride); + const size_t lhs_packed_offset = kai_get_lhs_packed_offset_lhs_quant_pack_qai8dxp_f32( + 0, CountK, mr, kr, sr); + + const float* src_ptr = reinterpret_cast(reinterpret_cast(A) + lhs_offset); + void* dst_ptr = QuantA + lhs_packed_offset; + + kai_run_lhs_quant_pack_qai8dxp_f32(CountM, CountK, mr, kr, sr, 0, src_ptr, src_stride, dst_ptr); +} +#endif + void QuantizeARow_CompInt8( size_t BlkLen, @@ -1399,4 +1439,47 @@ SQ4BitGemmKernel_CompInt8( return CountM; } +#ifdef USE_KLEIDIAI +void +SQ4BitGemmKernel_Packed_CompInt8( + size_t BlkLen, + const std::byte* QuantA, + const std::byte* PackedQuantBData, + float* C, + const size_t RangeStartM, + const size_t RangeCountM, + const size_t RangeStartN, + const size_t RangeCountN, + size_t CountK, + size_t ldc, + const float* Bias +) +{ + const kai_matmul_clamp_f32_qai8dxp_qsi4c32p_ukernel ukernel = + RangeCountM == 1 && RangeStartM == 0? GetKleidiAIGemvUKernel() : GetKleidiAIGemmUKernel(); + + const size_t dst_stride = ldc * sizeof(float); + + const size_t lhs_packed_offset = ukernel.get_lhs_packed_offset(RangeStartM, CountK); + const size_t rhs_packed_offset = ukernel.get_rhs_packed_offset(RangeStartN, CountK, BlkLen); + const size_t dst_offset = ukernel.get_dst_offset(RangeStartM, RangeStartN, dst_stride); + + const void* lhs_ptr = QuantA + lhs_packed_offset; + const void* rhs_ptr = PackedQuantBData + rhs_packed_offset; + float* dst_ptr = reinterpret_cast(reinterpret_cast(C) + dst_offset); + + ukernel.run_matmul( + RangeCountM, RangeCountN, CountK, BlkLen, lhs_ptr, rhs_ptr, dst_ptr, dst_stride, sizeof(float), + -std::numeric_limits::max(), std::numeric_limits::max()); + + if (Bias != nullptr) { + for (size_t m = RangeStartM; m < RangeStartM + RangeCountM; m++) { + for (size_t n = RangeStartN; n < RangeStartN + RangeCountN; n++) { + C[m * ldc + n] += Bias[n]; + } + } + } +} +#endif + } // namespace sqnbitgemm_neon diff --git a/onnxruntime/core/optimizer/constant_folding.cc b/onnxruntime/core/optimizer/constant_folding.cc index e755b4bfa6364..e36eef672c1ed 100644 --- a/onnxruntime/core/optimizer/constant_folding.cc +++ b/onnxruntime/core/optimizer/constant_folding.cc @@ -21,7 +21,16 @@ ConstantFolding::ConstantFolding(const IExecutionProvider& execution_provider, const ConfigOptions& config_options, const InlinedHashSet& compatible_execution_providers, const InlinedHashSet& excluded_initializers) noexcept - : GraphTransformer("ConstantFolding", compatible_execution_providers), + : ConstantFolding("ConstantFolding", execution_provider, skip_dequantize_linear, config_options, compatible_execution_providers, excluded_initializers) { +} + +ConstantFolding::ConstantFolding(const std::string& name, + const IExecutionProvider& execution_provider, + bool skip_dequantize_linear, + const ConfigOptions& config_options, + const InlinedHashSet& compatible_execution_providers, + const InlinedHashSet& excluded_initializers) noexcept + : GraphTransformer(name, compatible_execution_providers), skip_dequantize_linear_(skip_dequantize_linear), config_options_(config_options), excluded_initializers_(excluded_initializers), @@ -144,7 +153,7 @@ Status ConstantFolding::ApplyImpl(Graph& graph, bool& modified, int graph_level, for (NodeIndex i : order) { auto* node = graph.GetNode(i); - if (!node) { + if (!node || !AllowConstantFolding(*node)) { continue; } diff --git a/onnxruntime/core/optimizer/constant_folding.h b/onnxruntime/core/optimizer/constant_folding.h index 14eb2a9c5f06b..29bc67d560788 100644 --- a/onnxruntime/core/optimizer/constant_folding.h +++ b/onnxruntime/core/optimizer/constant_folding.h @@ -28,6 +28,24 @@ class ConstantFolding : public GraphTransformer { const InlinedHashSet& compatible_execution_providers = {}, const InlinedHashSet& excluded_initializers = {}) noexcept; + protected: + /** + * Same as the constructor above but with a name provided by derived class. + */ + ConstantFolding(const std::string& name, + const IExecutionProvider& execution_provider, + bool skip_dequantize_linear, + const ConfigOptions& config_options, + const InlinedHashSet& compatible_execution_providers = {}, + const InlinedHashSet& excluded_initializers = {}) noexcept; + /** + * Derived class can implement this virtual function to limit the nodes that can be constant folded. + */ + virtual bool AllowConstantFolding(const Node& node) const { + ORT_UNUSED_PARAMETER(node); + return true; + } + private: Status ApplyImpl(Graph& graph, bool& modified, int graph_level, const logging::Logger& logger) const override; diff --git a/onnxruntime/core/optimizer/conv_activation_fusion.cc b/onnxruntime/core/optimizer/conv_activation_fusion.cc index ea9d8605e2417..71c8667a89b1d 100644 --- a/onnxruntime/core/optimizer/conv_activation_fusion.cc +++ b/onnxruntime/core/optimizer/conv_activation_fusion.cc @@ -121,7 +121,7 @@ class ConvActivationSelector : public NodeSelector { if (!graph_utils::IsSupportedOptypeVersionAndDomain(*next_node, "Relu", {6, 13, 14})) { return std::nullopt; } - } else if (node_ep.empty() || node_ep == kCpuExecutionProvider || node_ep == kJsExecutionProvider) { + } else if (node_ep.empty() || node_ep == kCpuExecutionProvider || node_ep == kJsExecutionProvider || node_ep == kWebGpuExecutionProvider) { if (!is_supported_non_cuda_rocm_ep_activation(*next_node) && !graph_utils::IsSupportedOptypeVersionAndDomain(*next_node, "HardSigmoid", {6})) { return std::nullopt; diff --git a/onnxruntime/core/optimizer/gather_fusion.cc b/onnxruntime/core/optimizer/gather_fusion.cc index 2bde320786130..9732ec2587b2a 100644 --- a/onnxruntime/core/optimizer/gather_fusion.cc +++ b/onnxruntime/core/optimizer/gather_fusion.cc @@ -273,7 +273,8 @@ Status GatherSliceToSplitFusion::ApplyImpl(Graph& graph, bool& modified, int gra split_initializer_proto.add_dims(static_cast(split_values.size())); split_initializer_proto.mutable_int64_data()->Add(split_values.begin(), split_values.end()); NodeArg* split_initializer_arg = &graph_utils::AddInitializer(graph, split_initializer_proto); - Node& split_node = graph.AddNode(nodes_to_fuse[0].get().Name() + "/GatherSliceToSplitFusion/", "Split", "Split for Fused Gather nodes", + const auto split_node_name = graph.GenerateNodeName(nodes_to_fuse[0].get().Name() + "/GatherSliceToSplitFusion"); + Node& split_node = graph.AddNode(split_node_name, "Split", "Split for Fused Gather nodes", {graph.GetNodeArg(node_arg->Name()), split_initializer_arg}, split_outputs); split_node.AddAttribute("axis", axis); split_node.SetExecutionProviderType(nodes_to_fuse[0].get().GetExecutionProviderType()); diff --git a/onnxruntime/core/optimizer/graph_optimizer_registry.cc b/onnxruntime/core/optimizer/graph_optimizer_registry.cc new file mode 100644 index 0000000000000..8ede372470485 --- /dev/null +++ b/onnxruntime/core/optimizer/graph_optimizer_registry.cc @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/optimizer/graph_optimizer_registry.h" +#include "core/optimizer/graph_transformer_utils.h" +#include "core/optimizer/selection_and_optimization_func.h" +#include "core/optimizer/qdq_transformer/constant_folding_dq_node.h" + +using namespace onnxruntime; +using namespace ::onnxruntime::common; + +namespace onnxruntime { +#if !defined(ORT_MINIMAL_BUILD) +GraphOptimizerRegistry::GraphOptimizerRegistry(const onnxruntime::SessionOptions* sess_options, + const onnxruntime::IExecutionProvider* cpu_ep, + const logging::Logger* logger) : session_options_(sess_options), + cpu_ep_(cpu_ep), + logger_(logger) { + auto status = CreatePredefinedSelectionFuncs(); + ORT_ENFORCE(status.IsOK(), "Could not create pre-defined selection functions. Error Message: ", + status.ErrorMessage()); +} + +Status GraphOptimizerRegistry::CreatePredefinedSelectionFuncs() { + transformer_name_to_selection_func_[kConstantFoldingDQ] = ConstantFoldingDQFuncs::Select; + + return Status::OK(); +} + +std::optional GraphOptimizerRegistry::GetSelectionFunc(std::string& name) const { + auto lookup = transformer_name_to_selection_func_.find(name); + if (lookup != transformer_name_to_selection_func_.end()) { + return transformer_name_to_selection_func_.at(name); + } + LOGS(*logger_, WARNING) << "Can't find selection function of " << name; + return std::nullopt; +} +#else +GraphOptimizerRegistry::GraphOptimizerRegistry(const onnxruntime::SessionOptions* sess_options, + const onnxruntime::IExecutionProvider* cpu_ep, + const logging::Logger* logger) : session_options_(sess_options), + cpu_ep_(cpu_ep), + logger_(logger) {} + +std::optional GraphOptimizerRegistry::GetSelectionFunc(std::string& /*name*/) const { + return std::nullopt; +} +#endif +} // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/graph_optimizer_registry.h b/onnxruntime/core/optimizer/graph_optimizer_registry.h new file mode 100644 index 0000000000000..15c9287c0eac8 --- /dev/null +++ b/onnxruntime/core/optimizer/graph_optimizer_registry.h @@ -0,0 +1,77 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/common/inlined_containers.h" +#include "core/common/logging/logging.h" +#include "core/common/common.h" +#include "core/optimizer/graph_transformer.h" +#include "core/framework/execution_providers.h" +#include "core/framework/compute_capability.h" + +namespace onnxruntime { +/** + * Optimizer's selection function: Selects a set of nodes from a given graph for optimization. Additional key/value strings can be provided to configure the optimizer. + * If needed, use graph_optimizer_registry to access the session options, the CPU EP and the logger. + * + * Optimizer's optimization function: Gets the nodes in ComputeCapability from nodes_to_optimize. Use graph_optimizer_registry to access the session options, the CPU EP + * and the logger if needed to create the optimizer. Run optimization on the nodes/subgraph, and finally, update the ComputeCapability. + * + */ +using KeyValueConfig = std::unordered_map; +using SelectionFunc = std::function>(const GraphViewer&, + const KeyValueConfig&, + const GraphOptimizerRegistry& graph_optimizer_registry)>; +using OptimizationFunc = std::function; + +/** + * A registration/lookup class for re-usable optimizers for EPs. + */ +class GraphOptimizerRegistry { + public: + /** + * The constructor takes in session options, the CPU EP and a logger as these are required by some optimizers. + */ + GraphOptimizerRegistry(const onnxruntime::SessionOptions* sess_options, + const onnxruntime::IExecutionProvider* cpu_ep, + const logging::Logger* logger); + + /** + * Get optimizer selection function. If the optimizer name can't be found, return nullopt. + */ + std::optional GetSelectionFunc(std::string& name) const; + + /** + * Get CPU EP. + */ + const onnxruntime::IExecutionProvider& GetCpuEp() const { return *cpu_ep_; } + + /** + * Get Session Options. + */ + const onnxruntime::SessionOptions& GetSessionOptions() const { return *session_options_; } + + /** + * Get Logger. + */ + const logging::Logger* GetLogger() const { return logger_; } + + private: + const onnxruntime::SessionOptions* session_options_; + const onnxruntime::IExecutionProvider* cpu_ep_; + const logging::Logger* logger_; + +#if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) + InlinedHashMap transformer_name_to_selection_func_; + + /** + * Create pre-defined selection functions. + */ + Status CreatePredefinedSelectionFuncs(); +#endif +}; +} // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/graph_transformer_mgr.cc b/onnxruntime/core/optimizer/graph_transformer_mgr.cc index 039283bb2d4e1..83c3f70799987 100644 --- a/onnxruntime/core/optimizer/graph_transformer_mgr.cc +++ b/onnxruntime/core/optimizer/graph_transformer_mgr.cc @@ -27,6 +27,9 @@ common::Status GraphTransformerManager::ApplyTransformers(Graph& graph, Transfor } for (unsigned step = 0; step < steps_; ++step) { + if (IsLoadCancellationFlagSet()) { + return ORT_MAKE_STATUS(ONNXRUNTIME, MODEL_LOAD_CANCELED, "Graph transformation canceled due to user request."); + } bool graph_changed = false; for (const auto& transformer : transformers->second) { if (step > 0 && transformer->ShouldOnlyApplyOnce()) diff --git a/onnxruntime/core/optimizer/graph_transformer_mgr.h b/onnxruntime/core/optimizer/graph_transformer_mgr.h index ed66302434ab2..eab57f12bfcbb 100644 --- a/onnxruntime/core/optimizer/graph_transformer_mgr.h +++ b/onnxruntime/core/optimizer/graph_transformer_mgr.h @@ -24,6 +24,16 @@ class GraphTransformerManager { // Get the maximum number of graph transformation steps common::Status GetSteps(unsigned& steps) const; + // Set the cancellation flag ptr from session_options + void SetLoadCancellationFn(CheckLoadCancellationFn check_load_cancellation_fn) { + check_load_cancellation_fn_ = std::move(check_load_cancellation_fn); + } + + // Get the cancellation flag ptr + bool IsLoadCancellationFlagSet() const noexcept { + return check_load_cancellation_fn_ && check_load_cancellation_fn_(); + } + // Register a transformer with a level. common::Status Register(std::unique_ptr transformer, TransformerLevel level); @@ -38,5 +48,6 @@ class GraphTransformerManager { InlinedHashMap>> level_to_transformer_map_; InlinedHashMap transformers_info_; + CheckLoadCancellationFn check_load_cancellation_fn_; }; } // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/graph_transformer_utils.cc b/onnxruntime/core/optimizer/graph_transformer_utils.cc index 9684394da0520..eae2a464cef7e 100644 --- a/onnxruntime/core/optimizer/graph_transformer_utils.cc +++ b/onnxruntime/core/optimizer/graph_transformer_utils.cc @@ -296,17 +296,19 @@ InlinedVector> GenerateTransformers( onnxruntime::kCudaExecutionProvider, onnxruntime::kRocmExecutionProvider, onnxruntime::kDmlExecutionProvider}; - const InlinedHashSet cpu_rocm_acl_armnn_js_eps = {onnxruntime::kCpuExecutionProvider, - onnxruntime::kRocmExecutionProvider, - onnxruntime::kAclExecutionProvider, - onnxruntime::kArmNNExecutionProvider, - onnxruntime::kJsExecutionProvider}; - const InlinedHashSet cpu_cuda_rocm_acl_armnn_js_eps = {onnxruntime::kCpuExecutionProvider, - onnxruntime::kCudaExecutionProvider, - onnxruntime::kRocmExecutionProvider, - onnxruntime::kAclExecutionProvider, - onnxruntime::kArmNNExecutionProvider, - onnxruntime::kJsExecutionProvider}; + const InlinedHashSet cpu_rocm_acl_armnn_js_webgpu_eps = {onnxruntime::kCpuExecutionProvider, + onnxruntime::kRocmExecutionProvider, + onnxruntime::kAclExecutionProvider, + onnxruntime::kArmNNExecutionProvider, + onnxruntime::kJsExecutionProvider, + onnxruntime::kWebGpuExecutionProvider}; + const InlinedHashSet cpu_cuda_rocm_acl_armnn_js_webgpu_eps = {onnxruntime::kCpuExecutionProvider, + onnxruntime::kCudaExecutionProvider, + onnxruntime::kRocmExecutionProvider, + onnxruntime::kAclExecutionProvider, + onnxruntime::kArmNNExecutionProvider, + onnxruntime::kJsExecutionProvider, + onnxruntime::kWebGpuExecutionProvider}; const InlinedHashSet cpu_dml_acl_eps = {onnxruntime::kCpuExecutionProvider, onnxruntime::kDmlExecutionProvider, onnxruntime::kAclExecutionProvider}; @@ -338,7 +340,7 @@ InlinedVector> GenerateTransformers( transformers.emplace_back(std::make_unique(cpu_dml_acl_eps)); transformers.emplace_back(std::make_unique(cpu_acl_eps)); - transformers.emplace_back(std::make_unique(cpu_rocm_acl_armnn_js_eps)); + transformers.emplace_back(std::make_unique(cpu_rocm_acl_armnn_js_webgpu_eps)); transformers.emplace_back(std::make_unique(cpu_acl_cuda_dml_rocm_eps, level)); transformers.emplace_back(std::make_unique(cpu_acl_cuda_dml_rocm_eps, level)); diff --git a/onnxruntime/core/optimizer/layout_transformation/layout_transformation.cc b/onnxruntime/core/optimizer/layout_transformation/layout_transformation.cc index 56f7d28cd5b77..2754eebf75421 100644 --- a/onnxruntime/core/optimizer/layout_transformation/layout_transformation.cc +++ b/onnxruntime/core/optimizer/layout_transformation/layout_transformation.cc @@ -81,6 +81,15 @@ bool ConvertNodeLayout(const api::NodeRef& node) { } #endif +// NHWC for Resize operator is not implemented on kWebGpuExecutionProvider +#if defined(USE_WEBGPU) + if (node.GetExecutionProviderType() == kWebGpuExecutionProvider) { + if (node.OpType() == "Resize") { + return false; + } + } +#endif + #if defined(USE_CUDA) && ENABLE_CUDA_NHWC_OPS if (node.GetExecutionProviderType() == kCudaExecutionProvider) { if (layout_sensitive_ops.count(node.OpType())) { @@ -136,10 +145,14 @@ Status TransformLayoutForEP(Graph& graph, bool& modified, const IExecutionProvid } if (ConvertNodeLayout(*node)) { + // domain kMSInternalNHWCDomain uses OpType "Conv" for both Conv and FusedConv. + // So, change the OpType to "Conv" for FusedConv. + std::string_view op_type = node->OpType() == "FusedConv" ? "Conv" : node->OpType(); + // if already transformed then change the domain to kMSInternalNHWCDomain this way the EP // knows this op is in the expected format. if (node->GetAttributeIntDefault("channels_last", 0) == 1) { - SwapNodeOpTypeAndDomain(*api_graph, *node, node->OpType(), kMSInternalNHWCDomain); + SwapNodeOpTypeAndDomain(*api_graph, *node, op_type, kMSInternalNHWCDomain); // Changing the domain for the node requires creating a new node and replacing the old one // therefore set the modified flag. modified = true; @@ -166,7 +179,7 @@ Status TransformLayoutForEP(Graph& graph, bool& modified, const IExecutionProvid // Except for resize and convolution ops, all the other layout sensitive ops only require layout transformation // for 0th input and output. For resize, add the other relevant inputs which need conversion. For Conv - layout // transformer only converts layout for 0th input, weights should be handled by every EP. - if (node->OpType() == "Resize") { + if (op_type == "Resize") { // Older versions of resize have a bug where ROI and Scales cannot be made empty inputs. To handle this case, // we need to jump a few extra hoops to make sure its inputs are correctly handled. // @@ -196,7 +209,7 @@ Status TransformLayoutForEP(Graph& graph, bool& modified, const IExecutionProvid WrapTransposesAroundNode(*api_graph, *node, {&input_perm}, {&output_perm}); } - SwapNodeOpTypeAndDomain(*api_graph, *node, node->OpType(), kMSInternalNHWCDomain); + SwapNodeOpTypeAndDomain(*api_graph, *node, op_type, kMSInternalNHWCDomain); modified = true; } } diff --git a/onnxruntime/core/optimizer/qdq_transformer/constant_folding_dq_node.cc b/onnxruntime/core/optimizer/qdq_transformer/constant_folding_dq_node.cc new file mode 100644 index 0000000000000..a2f46d6ae693c --- /dev/null +++ b/onnxruntime/core/optimizer/qdq_transformer/constant_folding_dq_node.cc @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/optimizer/qdq_transformer/constant_folding_dq_node.h" +#include "core/optimizer/graph_optimizer_registry.h" +#include "core/graph/graph_utils.h" + +namespace onnxruntime { + +ConstantFoldingDQ::ConstantFoldingDQ(const IExecutionProvider& execution_provider, + bool skip_dequantize_linear, + const ConfigOptions& config_options, + const InlinedHashSet& node_index_set, + const InlinedHashSet& compatible_execution_providers, + const InlinedHashSet& excluded_initializers) noexcept + : ConstantFolding("ConstantFoldingDQ", execution_provider, skip_dequantize_linear, config_options, compatible_execution_providers, excluded_initializers), + node_index_set_(node_index_set) {} + +bool ConstantFoldingDQ::AllowConstantFolding(const Node& node) const { + if (node_index_set_.find(node.Index()) != node_index_set_.end()) { + return true; + } + return false; +} + +} // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/qdq_transformer/constant_folding_dq_node.h b/onnxruntime/core/optimizer/qdq_transformer/constant_folding_dq_node.h new file mode 100644 index 0000000000000..7aed87fa06adb --- /dev/null +++ b/onnxruntime/core/optimizer/qdq_transformer/constant_folding_dq_node.h @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/optimizer/graph_transformer.h" +#include "core/optimizer/constant_folding.h" +#include "core/framework/ort_value.h" +#include +#include "core/framework/execution_provider.h" + +namespace onnxruntime { + +/** +@class ConstantFoldingDQ + +It's the derived class from ConstantFolding. +*/ +class ConstantFoldingDQ : public ConstantFolding { + public: + /*! Constant folding will not be applied to nodes that have one of initializers from excluded_initializers as input. + \param execution_provider Execution provider instance to execute constant folding. + */ + ConstantFoldingDQ(const IExecutionProvider& execution_provider, + bool skip_dequantize_linear, + const ConfigOptions& config_options, + const InlinedHashSet& node_index_set, + const InlinedHashSet& compatible_execution_providers = {}, + const InlinedHashSet& excluded_initializers = {}) noexcept; + + bool AllowConstantFolding(const Node& node) const override; + + private: + InlinedHashSet node_index_set_; +}; + +} // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/selection_and_optimization_func.cc b/onnxruntime/core/optimizer/selection_and_optimization_func.cc new file mode 100644 index 0000000000000..151c61952a631 --- /dev/null +++ b/onnxruntime/core/optimizer/selection_and_optimization_func.cc @@ -0,0 +1,99 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "selection_and_optimization_func.h" +#include "core/graph/graph_utils.h" +#include "core/framework/compute_capability.h" +#include "core/optimizer/qdq_transformer/constant_folding_dq_node.h" + +namespace onnxruntime { + +std::vector> ConstantFoldingDQFuncs::Select(const GraphViewer& graph_viewer, + const KeyValueConfig& /*config*/, + const GraphOptimizerRegistry& /*graph_optimizer_registry*/) { + std::vector> result; + std::unique_ptr sub_graph = std::make_unique(); + const std::vector& node_index = graph_viewer.GetNodesInTopologicalOrder(ExecutionOrder::PRIORITY_BASED /*priority-based topological sort*/); + InitializedTensorSet constant_inputs; + const InlinedHashSet excluded_initializers; + + // Select DequantizeLinear node where all inputs are constant + for (const auto& index : node_index) { + const auto& node = graph_viewer.GetNode(index); + if (node->OpType() != "DequantizeLinear") { + continue; + } + if (!graph_utils::AllNodeInputsAreConstant(graph_viewer.GetGraph(), *node, constant_inputs, excluded_initializers)) { + continue; + } + sub_graph->nodes.push_back(index); + } + + result.push_back(std::make_unique(std::move(sub_graph))); + result.back()->optimization_func = ConstantFoldingDQFuncs::Optimize; + return result; +} + +Status ConstantFoldingDQFuncs::Optimize(Graph& graph, + const ComputeCapability& optimization_cc, + ComputeCapability& cc_to_update, + const GraphOptimizerRegistry& graph_optimizer_registry) { + std::string optimizer_name = kConstantFoldingDQ; + std::unordered_set original_initializers_to_remove; + std::unordered_set new_initializers_to_add; + InlinedHashSet dq_node_index_set; + + // iterate the nodes in node_to_optimize to: + // 1. get original initializers to remove + // 2. add new initializers + // 3. create dq node index set + for (const auto& index : optimization_cc.sub_graph->nodes) { + auto node = graph.GetNode(index); + if (node->OpType() != "DequantizeLinear") { + continue; + } + auto input_0 = node->InputDefs()[0]; + auto output_0 = node->OutputDefs()[0]; + original_initializers_to_remove.insert(input_0->Name()); + new_initializers_to_add.insert(output_0->Name()); + dq_node_index_set.insert(index); + } + + static auto transformer = std::make_unique(graph_optimizer_registry.GetCpuEp(), + false /*skip_dequantize_linear*/, + graph_optimizer_registry.GetSessionOptions().config_options, + dq_node_index_set); + + bool modified = false; + ORT_RETURN_IF_ERROR(transformer->Apply(graph, modified, *graph_optimizer_registry.GetLogger())); + + // update the overall ComputeCapability + std::vector updated_nodes; + for (auto index : cc_to_update.sub_graph->nodes) { + if (dq_node_index_set.find(index) != dq_node_index_set.end()) { + continue; + } + updated_nodes.push_back(index); + } + cc_to_update.sub_graph->nodes = updated_nodes; + + auto meta_def = cc_to_update.sub_graph->GetMutableMetaDef(); + std::vector updated_constant_initializers; + + for (auto constant_initializer : meta_def->constant_initializers) { + if (original_initializers_to_remove.find(constant_initializer) != original_initializers_to_remove.end()) { + continue; + } + updated_constant_initializers.push_back(constant_initializer); + } + + for (auto constant_initializer : new_initializers_to_add) { + updated_constant_initializers.push_back(constant_initializer); + } + + meta_def->constant_initializers = updated_constant_initializers; + + return Status::OK(); +} + +} // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/selection_and_optimization_func.h b/onnxruntime/core/optimizer/selection_and_optimization_func.h new file mode 100644 index 0000000000000..6ad62518833b0 --- /dev/null +++ b/onnxruntime/core/optimizer/selection_and_optimization_func.h @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/optimizer/graph_optimizer_registry.h" +#include "core/framework/compute_capability.h" +#include "core/graph/graph_viewer.h" + +namespace onnxruntime { +static const std::string kConstantFoldingDQ = "ConstantFoldingDQ"; + +/** + * Optimizer's selection function: Selects a set of nodes from a given graph for optimization. Additional key/value strings can be provided to configure the optimizer. + * If needed, use graph_optimizer_registry to access the session options, the CPU EP and the logger. + * + * Optimizer's optimization function: Gets the nodes in ComputeCapability from nodes_to_optimize. Use graph_optimizer_registry to access the session options, the CPU EP + * and the logger if needed to create the optimizer. Run optimization on the nodes/subgraph, and finally, update the ComputeCapability. + * + */ + +struct ConstantFoldingDQFuncs { + static std::vector> Select(const GraphViewer& graph_viewer, + const KeyValueConfig& configs, + const GraphOptimizerRegistry& graph_optimizer_registry); + static Status Optimize(Graph& graph, + const ComputeCapability& optimization_cc, + ComputeCapability& cc_to_update, + const GraphOptimizerRegistry& graph_optimizer_registry); +}; +} // namespace onnxruntime diff --git a/onnxruntime/core/platform/windows/dll_load_error.cc b/onnxruntime/core/platform/windows/dll_load_error.cc new file mode 100644 index 0000000000000..94471e76ffd71 --- /dev/null +++ b/onnxruntime/core/platform/windows/dll_load_error.cc @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include +#include +#pragma comment(lib, "dbghelp.lib") +#include +#include +#include +#include "dll_load_error.h" + +struct HMODULE_Deleter { + typedef HMODULE pointer; + void operator()(HMODULE h) { FreeLibrary(h); } +}; + +using ModulePtr = std::unique_ptr; + +// If a DLL fails to load, this will try loading the DLL and then its dependencies recursively +// until it finds a missing file, then will report which file is missing and what the dependency +// chain is. +std::wstring DetermineLoadLibraryError(const wchar_t* filename_in, DWORD flags) { + std::wstring error(L"Error loading"); + + std::wstring filename{filename_in}; + while (filename.size()) { + error += std::wstring(L" \"") + filename + L"\""; + + // We use DONT_RESOLVE_DLL_REFERENCES instead of LOAD_LIBRARY_AS_DATAFILE because the latter will not process the import table + // and will result in the IMAGE_IMPORT_DESCRIPTOR table names being uninitialized. + ModulePtr hModule = ModulePtr{LoadLibraryExW(filename.c_str(), NULL, flags | DONT_RESOLVE_DLL_REFERENCES)}; + if (!hModule) { + error += L" which is missing."; + return error; + } + + // Get the address of the Import Directory + ULONG size{}; + IMAGE_IMPORT_DESCRIPTOR* import_desc = reinterpret_cast(ImageDirectoryEntryToData(hModule.get(), TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size)); + if (!import_desc) { + error += L" No import directory found."; // This is unexpected, and I'm not sure how it could happen but we handle it just in case. + return error; + } + + // Iterate through the import descriptors to see which dependent DLL can't load + filename.clear(); + flags = 0; // Dependent libraries are relative, and flags like LOAD_WITH_ALTERED_SEARCH_PATH is undefined for those. + for (; import_desc->Characteristics; import_desc++) { + const char* dll_name = reinterpret_cast(reinterpret_cast(hModule.get()) + import_desc->Name); + // Try to load the dependent DLL, and if it fails, we loop again with this as the DLL and we'll be one step closer to the missing file. + ModulePtr hDepModule{LoadLibrary(dll_name)}; + if (!hDepModule) { + filename = std::wstring(dll_name, dll_name + strlen(dll_name)); + error += L" which depends on"; + break; + } + } + } + error += L" But no dependency issue could be determined."; + return error; +} diff --git a/onnxruntime/core/platform/windows/dll_load_error.h b/onnxruntime/core/platform/windows/dll_load_error.h new file mode 100644 index 0000000000000..019adfd9e16e4 --- /dev/null +++ b/onnxruntime/core/platform/windows/dll_load_error.h @@ -0,0 +1 @@ +std::wstring DetermineLoadLibraryError(const wchar_t* filename, DWORD flags); diff --git a/onnxruntime/core/platform/windows/env.cc b/onnxruntime/core/platform/windows/env.cc index 4fccad6dfeb37..9fdd323b365d6 100644 --- a/onnxruntime/core/platform/windows/env.cc +++ b/onnxruntime/core/platform/windows/env.cc @@ -39,6 +39,7 @@ limitations under the License. #include #include "core/platform/path_lib.h" // for LoopDir() +#include "core/platform/windows/dll_load_error.h" EXTERN_C IMAGE_DOS_HEADER __ImageBase; @@ -704,17 +705,18 @@ Status WindowsEnv::LoadDynamicLibrary(const PathString& wlibrary_filename, bool static constexpr DWORD bufferLength = 64 * 1024; std::wstring s(bufferLength, '\0'); FormatMessageW( - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)s.data(), - 0, NULL); + bufferLength, NULL); + s.erase(std::remove(s.begin(), s.end(), L'\r'), s.end()); + s.erase(std::remove(s.begin(), s.end(), L'\n'), s.end()); std::wostringstream oss; - oss << L"LoadLibrary failed with error " << error_code << L" \"" << s.c_str() << L"\" when trying to load \"" << wlibrary_filename << L"\""; + oss << DetermineLoadLibraryError(wlibrary_filename.c_str(), LOAD_WITH_ALTERED_SEARCH_PATH) + << L" (Error " << error_code << ": \"" << s.c_str() << "\")"; std::wstring errmsg = oss.str(); - // TODO: trim the ending '\r' and/or '\n' common::Status status(common::ONNXRUNTIME, common::FAIL, ToUTF8String(errmsg)); return status; } diff --git a/onnxruntime/core/providers/acl/acl_execution_provider.cc b/onnxruntime/core/providers/acl/acl_execution_provider.cc index ede476ff74d1b..def1d5e4b704c 100644 --- a/onnxruntime/core/providers/acl/acl_execution_provider.cc +++ b/onnxruntime/core/providers/acl/acl_execution_provider.cc @@ -153,6 +153,7 @@ std::shared_ptr ACLExecutionProvider::GetKernelRegistry() const std::vector> ACLExecutionProvider::GetCapability(const onnxruntime::GraphViewer& graph, const IKernelLookup& kernel_lookup, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant*) const { std::vector> result; for (const auto& node : graph.Nodes()) { diff --git a/onnxruntime/core/providers/acl/acl_execution_provider.h b/onnxruntime/core/providers/acl/acl_execution_provider.h index d635e56add30b..80e4aaaf021e3 100755 --- a/onnxruntime/core/providers/acl/acl_execution_provider.h +++ b/onnxruntime/core/providers/acl/acl_execution_provider.h @@ -39,6 +39,7 @@ class ACLExecutionProvider : public IExecutionProvider { std::vector> GetCapability( const onnxruntime::GraphViewer& graph, const IKernelLookup& kernel_lookup, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* resource_accountant) const override; Status OnRunStart(const onnxruntime::RunOptions&) override; diff --git a/onnxruntime/core/providers/cann/cann_execution_provider.cc b/onnxruntime/core/providers/cann/cann_execution_provider.cc index 07e83933a890c..be09eefba791b 100644 --- a/onnxruntime/core/providers/cann/cann_execution_provider.cc +++ b/onnxruntime/core/providers/cann/cann_execution_provider.cc @@ -1254,6 +1254,7 @@ GetSubGraphPartition(const std::vector& topological_order, const std: std::vector> CANNExecutionProvider::GetCapability(const onnxruntime::GraphViewer& graph_viewer, const IKernelLookup& kernel_lookup, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant*) const { std::vector> result; diff --git a/onnxruntime/core/providers/cann/cann_execution_provider.h b/onnxruntime/core/providers/cann/cann_execution_provider.h index 5ff935463a1c1..f28ae77e49f83 100644 --- a/onnxruntime/core/providers/cann/cann_execution_provider.h +++ b/onnxruntime/core/providers/cann/cann_execution_provider.h @@ -56,6 +56,7 @@ class CANNExecutionProvider : public IExecutionProvider { std::vector> GetCapability( const onnxruntime::GraphViewer& graph_viewer, const IKernelLookup& kernel_lookup, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* resource_accountant) const override; Status Compile(const std::vector& fused_nodes_and_graphs, diff --git a/onnxruntime/core/providers/cann/cann_utils.cc b/onnxruntime/core/providers/cann/cann_utils.cc index 95d7a462ca9d9..5b3f9e6731b34 100644 --- a/onnxruntime/core/providers/cann/cann_utils.cc +++ b/onnxruntime/core/providers/cann/cann_utils.cc @@ -220,7 +220,7 @@ bool FileExist(const std::string& file_name) { void GenerateHashValue(const std::string string, HashValue& hash_value) { uint32_t hash[4] = {0, 0, 0, 0}; - MurmurHash3::x86_128(string.data(), gsl::narrow_cast(string.size()), hash[0], &hash); + MurmurHash3::x86_128(string.data(), string.size(), hash[0], &hash); hash_value = hash[0] | (uint64_t(hash[1]) << 32); } diff --git a/onnxruntime/core/providers/coreml/builders/impl/activation_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/activation_op_builder.cc index 4481a5172966b..3fffc6d0a68c4 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/activation_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/activation_op_builder.cc @@ -97,7 +97,6 @@ Status ActivationOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const logging::Logger& logger) const { const auto& op_type(node.OpType()); -#if defined(COREML_ENABLE_MLPROGRAM) if (model_builder.CreateMLProgram()) { using namespace CoreML::Specification::MILSpec; // https://apple.github.io/coremltools/source/coremltools.converters.mil.mil.ops.defs.html#module-coremltools.converters.mil.mil.ops.defs.iOS15.activation @@ -166,9 +165,7 @@ Status ActivationOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, model_builder.AddOperation(std::move(op)); - } else -#endif // (COREML_ENABLE_MLPROGRAM) - { + } else { std::unique_ptr layer = model_builder.CreateNNLayer(node); if (op_type == "Sigmoid") { diff --git a/onnxruntime/core/providers/coreml/builders/impl/argmax_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/argmax_op_builder.cc index 6169090a36014..dfa01c8187741 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/argmax_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/argmax_op_builder.cc @@ -32,7 +32,6 @@ Status ArgMaxOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const int64_t keepdims = helper.Get("keepdims", 1); const bool removedim = keepdims != 1; -#if defined(COREML_ENABLE_MLPROGRAM) if (model_builder.CreateMLProgram()) { using namespace CoreML::Specification::MILSpec; // https://apple.github.io/coremltools/source/coremltools.converters.mil.mil.ops.defs.html#module-coremltools.converters.mil.mil.ops.defs.iOS15.reduction @@ -46,9 +45,7 @@ Status ArgMaxOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, // the output of ArgMax must be int32 AddOperationOutput(*op, *node.OutputDefs()[0], output_datatype); model_builder.AddOperation(std::move(op)); - } else -#endif // (COREML_ENABLE_MLPROGRAM) - { + } else { auto* coreml_argmax = layer->mutable_argmax(); coreml_argmax->set_axis(axis); coreml_argmax->set_removedim(removedim); @@ -91,11 +88,9 @@ bool ArgMaxOpBuilder::IsOpSupportedImpl(const Node& node, return false; } -#if defined(COREML_ENABLE_MLPROGRAM) if (input_params.create_mlprogram) { return true; } -#endif // If there are multiple downstream nodes and cast (toint32) is one of them // not supported, exit here diff --git a/onnxruntime/core/providers/coreml/builders/impl/base_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/base_op_builder.cc index 2817f34bc64f2..9e7fcd788664c 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/base_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/base_op_builder.cc @@ -6,6 +6,7 @@ #include "core/providers/coreml/builders/helper.h" #include "core/providers/coreml/builders/impl/base_op_builder.h" #include "core/providers/coreml/builders/model_builder.h" +#include "core/providers/coreml/model/host_utils.h" #include "core/providers/shared/utils/utils.h" using namespace CoreML::Specification; @@ -113,10 +114,12 @@ bool BaseOpBuilder::IsInputDtypeSupport(const Node& node, size_t idx, return true; } +#if CAN_BUILD_COREML6_OR_LATER // only MLProgram support FP16 if (input_params.create_mlprogram && input_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT16) { return true; } +#endif LOGS(logger, VERBOSE) << "[" << node.OpType() << "] Input type: [" << input_type << "] is not currently supported"; return false; diff --git a/onnxruntime/core/providers/coreml/builders/impl/batch_norm_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/batch_norm_op_builder.cc index 442194cb31cbc..e547f2e42e527 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/batch_norm_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/batch_norm_op_builder.cc @@ -57,7 +57,6 @@ Status BatchNormalizationOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_bu const auto eps = helper.Get("epsilon", 1e-5f); const auto channels = scale_tensor.dims()[0]; -#if defined(COREML_ENABLE_MLPROGRAM) if (model_builder.CreateMLProgram()) { using namespace CoreML::Specification::MILSpec; // https://apple.github.io/coremltools/source/coremltools.converters.mil.mil.ops.defs.html#coremltools.converters.mil.mil.ops.defs.iOS15.normalization.batch_norm @@ -78,9 +77,7 @@ Status BatchNormalizationOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_bu AddOperationOutput(*op, *node.OutputDefs()[0]); model_builder.AddOperation(std::move(op)); - } else -#endif // (COREML_ENABLE_MLPROGRAM) - { + } else { auto* coreml_batch_norm = layer->mutable_batchnorm(); coreml_batch_norm->set_channels(channels); coreml_batch_norm->set_epsilon(eps); diff --git a/onnxruntime/core/providers/coreml/builders/impl/binary_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/binary_op_builder.cc index 0482620b269a4..d7c78e05362ed 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/binary_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/binary_op_builder.cc @@ -56,7 +56,6 @@ bool CheckIfBothInputShapesMatch(const Node& node, const logging::Logger& logger } } // namespace -#if defined(COREML_ENABLE_MLPROGRAM) static std::vector InferOutputShape(const std::vector& a, const std::vector& b) { std::vector output_shape; int64_t i_a = 0, j_b = 0; @@ -112,14 +111,12 @@ static void AddVariadicInputs(std::unique_ptr layer = model_builder.CreateNNLayer(node); if (op_type == "Add") { diff --git a/onnxruntime/core/providers/coreml/builders/impl/builder_utils.cc b/onnxruntime/core/providers/coreml/builders/impl/builder_utils.cc index 6f9bb35c27d80..684653aa21273 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/builder_utils.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/builder_utils.cc @@ -150,7 +150,6 @@ void CreateCoreMLWeight(CoreML::Specification::WeightParams& weight, gsl::span data); -#if defined(COREML_ENABLE_MLPROGRAM) // // MLProgram utils // @@ -174,6 +173,5 @@ void AddOperationOutput(COREML_SPEC::MILSpec::Operation& op, const NodeArg& outp /// Number of spatial dims in input. Generally rank - 2 (ignore N and C dims). void AddPadTypeAndPads(COREML_SPEC::MILSpec::Operation& op, ModelBuilder& model_builder, std::string_view op_type, const NodeAttrHelper& helper, int num_spatial_dims); -#endif // defined(COREML_ENABLE_MLPROGRAM) } // namespace coreml } // namespace onnxruntime diff --git a/onnxruntime/core/providers/coreml/builders/impl/cast_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/cast_op_builder.cc index 7c7363d4c81ad..8abee92451338 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/cast_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/cast_op_builder.cc @@ -27,9 +27,8 @@ class CastOpBuilder : public BaseOpBuilder { Status CastOpBuilder::AddToModelBuilderImpl([[maybe_unused]] ModelBuilder& model_builder, [[maybe_unused]] const Node& node, [[maybe_unused]] const logging::Logger& logger) const { -// This is a special handling case for ArgMax Op, where argmax is followed by a cast to int32 type. -// The ArgMax is fused with the Cast node and produces an int32 output. -#if defined(COREML_ENABLE_MLPROGRAM) + // This is a special handling case for ArgMax Op, where argmax is followed by a cast to int32 type. + // The ArgMax is fused with the Cast node and produces an int32 output. if (model_builder.CreateMLProgram()) { using namespace CoreML::Specification::MILSpec; // https://apple.github.io/coremltools/source/coremltools.converters.mil.mil.ops.defs.html#coremltools.converters.mil.mil.ops.defs.iOS15.elementwise_unary.cast @@ -73,7 +72,6 @@ Status CastOpBuilder::AddToModelBuilderImpl([[maybe_unused]] ModelBuilder& model AddOperationOutput(*op, *node.OutputDefs()[0], cast_to_type); model_builder.AddOperation(std::move(op)); } -#endif return Status::OK(); } @@ -134,7 +132,6 @@ bool CastOpBuilder::HasSupportedInputsImpl(const Node& node, [[maybe_unused]] co return false; } -#if defined(COREML_ENABLE_MLPROGRAM) if (input_params.create_mlprogram) { if ((input_type == ONNX_NAMESPACE::TensorProto_DataType_INT32 || input_type == ONNX_NAMESPACE::TensorProto_DataType_INT64 || @@ -152,7 +149,6 @@ bool CastOpBuilder::HasSupportedInputsImpl(const Node& node, [[maybe_unused]] co return false; } } -#endif // only support int64 coming from ArgMax (check for ArgMax is done in IsOpSupportedImpl()) if (input_type != ONNX_NAMESPACE::TensorProto_DataType_INT64) { diff --git a/onnxruntime/core/providers/coreml/builders/impl/clip_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/clip_op_builder.cc index f7046c213a8cb..9e68070a0e693 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/clip_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/clip_op_builder.cc @@ -64,7 +64,6 @@ Status ClipOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, bool has_min = min != std::numeric_limits::lowest(); bool has_max = max != std::numeric_limits::max(); -#if defined(COREML_ENABLE_MLPROGRAM) if (model_builder.CreateMLProgram()) { using namespace CoreML::Specification::MILSpec; @@ -121,9 +120,7 @@ Status ClipOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, AddOperationOutput(*op, output); model_builder.AddOperation(std::move(op)); - } else -#endif // defined(COREML_ENABLE_MLPROGRAM) - { + } else { // TODO: CoreML has a Clip layer for NeuralNetwork. Added in CoreML 4. We could potentially use that if available // to simplify. // https://apple.github.io/coremltools/mlmodel/Format/NeuralNetwork.html#cliplayerparams diff --git a/onnxruntime/core/providers/coreml/builders/impl/concat_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/concat_op_builder.cc index 9ea0030290abd..34ce2438095ad 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/concat_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/concat_op_builder.cc @@ -26,7 +26,6 @@ class ConcatOpBuilder : public BaseOpBuilder { Status ConcatOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, const logging::Logger& logger) const { -#if defined(COREML_ENABLE_MLPROGRAM) if (model_builder.CreateMLProgram()) { using namespace CoreML::Specification::MILSpec; // NOLINT @@ -45,7 +44,6 @@ Status ConcatOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, AddOperationOutput(*op, *node.OutputDefs()[0]); model_builder.AddOperation(std::move(op)); } else // NOLINT -#endif // defined(COREML_ENABLE_MLPROGRAM) { std::unique_ptr layer = model_builder.CreateNNLayer(node); diff --git a/onnxruntime/core/providers/coreml/builders/impl/conv_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/conv_op_builder.cc index 38125957bf481..18823bcc78d19 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/conv_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/conv_op_builder.cc @@ -52,7 +52,6 @@ Status ConvOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const N NodeAttrHelper helper(node); -#if defined(COREML_ENABLE_MLPROGRAM) if (model_builder.CreateMLProgram()) { using namespace CoreML::Specification::MILSpec; @@ -89,9 +88,7 @@ Status ConvOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const N AddOperationOutput(*conv_op, *node.OutputDefs()[0]); model_builder.AddOperation(std::move(conv_op)); - } else -#endif // defined(COREML_ENABLE_MLPROGRAM) - { + } else { std::unique_ptr layer = model_builder.CreateNNLayer(node); auto strides = helper.Get("strides", std::vector{1, 1}); @@ -225,14 +222,11 @@ bool ConvOpBuilder::IsOpSupportedImpl(const Node& node, const OpBuilderInputPara const auto& weight_name = input_defs[1]->Name(); const auto* weight = input_params.graph_viewer.GetConstantInitializer(weight_name); -#if defined(COREML_ENABLE_MLPROGRAM) if (input_params.create_mlprogram) { // ML Program supports non-const weight, 1D, 2D and 3D. // keep to 1D and 2D for consistency with the NeuralNetwork implementation for now. // add 3D support as/when needed. - } else -#endif // defined (COREML_ENABLE_MLPROGRAM) - { + } else { if (!weight) { LOGS(logger, VERBOSE) << "The weight of Conv [" << name << "] must be a constant initializer"; return false; @@ -257,7 +251,6 @@ bool ConvOpBuilder::IsOpSupportedImpl(const Node& node, const OpBuilderInputPara NodeAttrHelper helper(node); -#if defined(COREML_ENABLE_MLPROGRAM) // spec says same_lower is supported in CoreML 5. it lies. CoreML 6 is required otherwise you get // `Unexpected value for parameter pad_type[0] "same_lower" not in ("custom", "same", "valid").` // We _could_ manually calculate the pads, but not implementing that until we have a real use case to justify @@ -269,7 +262,6 @@ bool ConvOpBuilder::IsOpSupportedImpl(const Node& node, const OpBuilderInputPara return false; } } -#endif // there's no equivalent to allow a manual kernel shape in CoreML. // it's OK if a specified kernel_shape matches kH and kW dims of the weight input. diff --git a/onnxruntime/core/providers/coreml/builders/impl/convtranspose_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/convtranspose_op_builder.cc index 5b6d9d72ab3c9..2e2c898b0e10a 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/convtranspose_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/convtranspose_op_builder.cc @@ -28,7 +28,6 @@ class ConvTransposeOpBuilder : public BaseOpBuilder { Status ConvTransposeOpBuilder::AddToModelBuilderImpl([[maybe_unused]] ModelBuilder& model_builder, [[maybe_unused]] const Node& node, const logging::Logger& /*logger*/) const { -#if defined(COREML_ENABLE_MLPROGRAM) using namespace CoreML::Specification::MILSpec; // NOLINT const auto input_defs = node.InputDefs(); const auto output_defs = node.OutputDefs(); @@ -80,7 +79,6 @@ Status ConvTransposeOpBuilder::AddToModelBuilderImpl([[maybe_unused]] ModelBuild AddOperationOutput(*op, *output_defs[0]); model_builder.AddOperation(std::move(op)); -#endif // defined(COREML_ENABLE_MLPROGRAM) return Status::OK(); } diff --git a/onnxruntime/core/providers/coreml/builders/impl/depthtospace_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/depthtospace_op_builder.cc index fec14dfd093a0..1a74b1eea97fe 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/depthtospace_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/depthtospace_op_builder.cc @@ -33,7 +33,6 @@ Status DepthToSpaceOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, NodeAttrHelper helper(node); int64_t blocksize = *helper.GetInt64("blocksize"); // required attribute -#if defined(COREML_ENABLE_MLPROGRAM) if (model_builder.CreateMLProgram()) { using namespace CoreML::Specification::MILSpec; // NOLINT @@ -105,7 +104,6 @@ Status DepthToSpaceOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, model_builder.AddOperation(std::move(reshape2)); } } else // NOLINT -#endif // if defined(COREML_ENABLE_MLPROGRAM) { const auto& output_name = output_defs[0]->Name(); std::unique_ptr layer = model_builder.CreateNNLayer(node); diff --git a/onnxruntime/core/providers/coreml/builders/impl/gemm_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/gemm_op_builder.cc index e685c09ef43ca..4f84f7c36259c 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/gemm_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/gemm_op_builder.cc @@ -33,7 +33,6 @@ void GemmOpBuilder::AddInitializersToSkip(ModelBuilder& model_builder, const Nod const auto& input_defs(node.InputDefs()); const bool is_gemm = op == "Gemm"; -#if defined(COREML_ENABLE_MLPROGRAM) if (model_builder.CreateMLProgram()) { // we have to transpose the weight input of Gemm if transB is false, and potentially override the bias shape if (is_gemm) { @@ -58,9 +57,7 @@ void GemmOpBuilder::AddInitializersToSkip(ModelBuilder& model_builder, const Nod } } } - } else -#endif // defined(COREML_ENABLE_MLPROGRAM) - { + } else { // We have already embedded the weights (matrix B and C(if any)) into the coreml layer // No need to copy them later to reduce memory consumption model_builder.AddInitializerToSkip(input_defs[1]->Name()); @@ -123,7 +120,6 @@ Status GemmOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const N const auto K = transB ? b1 : b0; const auto N = transB ? b0 : b1; // we already checked it and dtype must be existed. -#if defined(COREML_ENABLE_MLPROGRAM) auto input_dtype = a.TypeAsProto()->tensor_type().elem_type(); if (model_builder.CreateMLProgram()) { using namespace CoreML::Specification::MILSpec; @@ -207,9 +203,7 @@ Status GemmOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const N AddOperationOutput(*matmul_op, *node.OutputDefs()[0]); model_builder.AddOperation(std::move(matmul_op)); } - } else -#endif // defined(COREML_ENABLE_MLPROGRAM) - { + } else { auto* coreml_inner_product = layer->mutable_innerproduct(); *layer->mutable_input()->Add() = a.Name(); diff --git a/onnxruntime/core/providers/coreml/builders/impl/gridsample_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/gridsample_op_builder.cc index 6dcf14c16f111..f558f423752e8 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/gridsample_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/gridsample_op_builder.cc @@ -42,7 +42,6 @@ class GridSampleOpBuilder : public BaseOpBuilder { Status GridSampleOpBuilder::AddToModelBuilderImpl([[maybe_unused]] ModelBuilder& model_builder, [[maybe_unused]] const Node& node, [[maybe_unused]] const logging::Logger& logger) const { -#if defined(COREML_ENABLE_MLPROGRAM) using namespace CoreML::Specification::MILSpec; // NOLINT // https://apple.github.io/coremltools/source/coremltools.converters.mil.mil.ops.defs.html#coremltools.converters.mil.mil.ops.defs.iOS15.image_resizing.resample @@ -80,7 +79,6 @@ Status GridSampleOpBuilder::AddToModelBuilderImpl([[maybe_unused]] ModelBuilder& AddOperationOutput(*op, *output_defs[0]); model_builder.AddOperation(std::move(op)); -#endif return Status::OK(); } diff --git a/onnxruntime/core/providers/coreml/builders/impl/normalization_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/normalization_op_builder.cc index b4dc8d1647ad0..c0db144602ee2 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/normalization_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/normalization_op_builder.cc @@ -49,7 +49,6 @@ Status NormalizationOpBuilder::AddToModelBuilderImpl( if (node.OpType() == "GroupNormalization") { return AddGroupNormToModelBuilderImpl(model_builder, node, logger); } -#if defined(COREML_ENABLE_MLPROGRAM) const auto& input_defs = node.InputDefs(); NodeAttrHelper helper(node); const auto& scale_tensor = *model_builder.GetConstantInitializer(input_defs[1]->Name()); @@ -94,7 +93,6 @@ Status NormalizationOpBuilder::AddToModelBuilderImpl( AddOperationOutput(*op, *node.OutputDefs()[0]); model_builder.AddOperation(std::move(op)); } -#endif // (COREML_ENABLE_MLPROGRAM) return Status::OK(); } @@ -103,7 +101,6 @@ Status NormalizationOpBuilder::AddGroupNormToModelBuilderImpl( [[maybe_unused]] ModelBuilder& model_builder, [[maybe_unused]] const Node& node, [[maybe_unused]] const logging::Logger& logger) const { -#if defined(COREML_ENABLE_MLPROGRAM) const auto& input_defs = node.InputDefs(); NodeAttrHelper helper(node); // Coreml hasn't supported GroupNorm yet. @@ -184,7 +181,6 @@ Status NormalizationOpBuilder::AddGroupNormToModelBuilderImpl( model_builder.AddOperation(std::move(mul)); model_builder.AddOperation(std::move(add)); } -#endif // (COREML_ENABLE_MLPROGRAM) return Status::OK(); } diff --git a/onnxruntime/core/providers/coreml/builders/impl/pool_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/pool_op_builder.cc index 17910ba6fd486..e43eef75007cc 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/pool_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/pool_op_builder.cc @@ -29,7 +29,6 @@ Status PoolOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const auto& op_type = node.OpType(); const auto& input_defs = node.InputDefs(); -#if defined(COREML_ENABLE_MLPROGRAM) if (model_builder.CreateMLProgram()) { using namespace CoreML::Specification::MILSpec; @@ -91,9 +90,7 @@ Status PoolOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, AddOperationOutput(*op, *node.OutputDefs()[0]); model_builder.AddOperation(std::move(op)); - } else -#endif // defined(COREML_ENABLE_MLPROGRAM) - { + } else { std::unique_ptr layer = model_builder.CreateNNLayer(node); auto* coreml_pool = layer->mutable_pooling(); diff --git a/onnxruntime/core/providers/coreml/builders/impl/reduction_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/reduction_op_builder.cc index d533b867bd454..a4609eb2a0584 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/reduction_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/reduction_op_builder.cc @@ -71,7 +71,6 @@ Status ReductionOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, co const bool keepdims = helper.Get("keepdims", 1) != 0; const bool noop_with_empty_axes = helper.Get("noop_with_empty_axes", 0) != 0; -#if defined(COREML_ENABLE_MLPROGRAM) if (model_builder.CreateMLProgram()) { using namespace CoreML::Specification::MILSpec; @@ -103,9 +102,7 @@ Status ReductionOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, co AddOperationOutput(*op, *node.OutputDefs()[0]); model_builder.AddOperation(std::move(op)); - } else -#endif // (COREML_ENABLE_MLPROGRAM) - { + } else { std::unique_ptr layer = model_builder.CreateNNLayer(node); if (op_type == "ReduceSum") { diff --git a/onnxruntime/core/providers/coreml/builders/impl/reshape_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/reshape_op_builder.cc index 27d24d9c21893..b35d6971623ed 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/reshape_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/reshape_op_builder.cc @@ -50,7 +50,6 @@ Status ReshapeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, // ReshapeHelper applies the ONNX rules to create the concrete output shape ReshapeHelper helper(TensorShape(input_shape), new_shape); -#if defined(COREML_ENABLE_MLPROGRAM) if (model_builder.CreateMLProgram()) { using namespace CoreML::Specification::MILSpec; @@ -64,9 +63,7 @@ Status ReshapeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, AddOperationOutput(*reshape_op, *node.OutputDefs()[0]); model_builder.AddOperation(std::move(reshape_op)); - } else -#endif // defined(COREML_ENABLE_MLPROGRAM) - { + } else { std::unique_ptr layer = model_builder.CreateNNLayer(node); *layer->mutable_reshapestatic()->mutable_targetshape() = {new_shape.cbegin(), new_shape.cend()}; diff --git a/onnxruntime/core/providers/coreml/builders/impl/resize_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/resize_op_builder.cc index 7ff66e4a79e37..837573003e515 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/resize_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/resize_op_builder.cc @@ -212,7 +212,6 @@ Status ResizeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const num_sizes = output_sizes.size(); } -#if defined(COREML_ENABLE_MLPROGRAM) if (model_builder.CreateMLProgram()) { using namespace CoreML::Specification::MILSpec; // NOLINT @@ -279,9 +278,7 @@ Status ResizeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const AddOperationOutput(*op, *output_defs[0]); model_builder.AddOperation(std::move(op)); - } else // NOLINT -#endif - { + } else { std::unique_ptr layer = model_builder.CreateNNLayer(node); auto* coreml_upsample = layer->mutable_upsample(); diff --git a/onnxruntime/core/providers/coreml/builders/impl/shape_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/shape_op_builder.cc index 243f949bdd48e..d1c87b033d323 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/shape_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/shape_op_builder.cc @@ -25,7 +25,6 @@ Status ShapeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const const logging::Logger& /*logger*/) const { const auto& input_defs = node.InputDefs(); -#if defined(COREML_ENABLE_MLPROGRAM) if (model_builder.CreateMLProgram()) { using namespace CoreML::Specification::MILSpec; NodeAttrHelper node_attr_helper{node}; @@ -63,9 +62,7 @@ Status ShapeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const AddOperationOutput(*op, *node.OutputDefs()[0], output_datatype); model_builder.AddOperation(std::move(op)); } - } else // NOLINT -#endif - { + } else { auto layer = model_builder.CreateNNLayer(node); layer->mutable_getshape(); *layer->mutable_input()->Add() = input_defs[0]->Name(); diff --git a/onnxruntime/core/providers/coreml/builders/impl/slice_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/slice_op_builder.cc index 6b3fe75fa592d..368e47e40f831 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/slice_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/slice_op_builder.cc @@ -127,7 +127,6 @@ Status SliceOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const SliceOp::PrepareForComputeMetadata compute_metadata{data_shape}; ORT_RETURN_IF_ERROR(PrepareSliceComputeMetadata(node, model_builder.GetGraphViewer(), compute_metadata)); -#if defined(COREML_ENABLE_MLPROGRAM) if (model_builder.CreateMLProgram()) { using namespace CoreML::Specification::MILSpec; // NOLINT // https://apple.github.io/coremltools/source/coremltools.converters.mil.mil.ops.defs.html#coremltools.converters.mil.mil.ops.defs.iOS15.tensor_transformation.slice_by_index @@ -178,9 +177,7 @@ Status SliceOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const model_builder.AddOperation(std::move(op)); - } else // NOLINT -#endif // defined(COREML_ENABLE_MLPROGRAM) - { + } else { auto layer = model_builder.CreateNNLayer(node); *layer->mutable_input()->Add() = input_defs[0]->Name(); *layer->mutable_output()->Add() = output_defs[0]->Name(); @@ -222,7 +219,6 @@ bool SliceOpBuilder::HasSupportedInputsImpl(const Node& node, return false; } -#ifdef COREML_ENABLE_MLPROGRAM // The [Doc](https://apple.github.io/coremltools/source/coremltools.converters.mil.mil.ops.defs.html#coremltools.converters.mil.mil.ops.defs.iOS15.tensor_transformation.slice_by_index) // says ML Program slice_by_index supports fp16 in CoreML 5 (iOS 15). // It's incorrect and CoreML 6+ (iOS16, CoreML spec version >= 7) is required otherwise only float is supported. @@ -230,13 +226,11 @@ bool SliceOpBuilder::HasSupportedInputsImpl(const Node& node, // CoreML 6:https://github.com/apple/coremltools/blob/c3ea4cf56fef1176417246c1b85363417f3e713d/coremltools/converters/mil/mil/ops/defs/iOS15/tensor_transformation.py#L495 if (input_params.create_mlprogram && input_params.coreml_version >= 6 && input_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT16) { - } else -#endif // nolint - if (input_type != ONNX_NAMESPACE::TensorProto_DataType_FLOAT && - input_type != ONNX_NAMESPACE::TensorProto_DataType_INT64) { - LOGS(logger, VERBOSE) << "[" << node.OpType() << "] Input type: [" << input_type << "] is not supported"; - return false; - } + } else if (input_type != ONNX_NAMESPACE::TensorProto_DataType_FLOAT && + input_type != ONNX_NAMESPACE::TensorProto_DataType_INT64) { + LOGS(logger, VERBOSE) << "[" << node.OpType() << "] Input type: [" << input_type << "] is not supported"; + return false; + } return true; } diff --git a/onnxruntime/core/providers/coreml/builders/impl/softmax_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/softmax_op_builder.cc index c6e331feed326..2411cd459fecd 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/softmax_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/softmax_op_builder.cc @@ -37,7 +37,6 @@ Status SoftmaxOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const auto axis = helper.Get("axis", axis_default_value); auto axis_nonnegative = HandleNegativeAxis(axis, data_shape.size()); -#if defined(COREML_ENABLE_MLPROGRAM) // CoreML's softmax match onnx's softmax behavior since opset 13. // For opset < 13, we need to reshape to 2D and set axis to -1 to simulate onnx softmax behavior. // [B,D,...](onnx softmax opset 12, axis=1)->[B,D*...](CoreML softmax, axis=-1)->[B,D,...](reshape back) @@ -78,9 +77,7 @@ Status SoftmaxOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, AddOperationOutput(*reshape2, *node.OutputDefs()[0]); model_builder.AddOperation(std::move(reshape2)); } - } else // NOLINT -#endif - { + } else { if (node.SinceVersion() >= 13 || (data_shape.size() == 2)) { auto* coreml_softmaxnd = layer->mutable_softmaxnd(); coreml_softmaxnd->set_axis(axis); diff --git a/onnxruntime/core/providers/coreml/builders/impl/split_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/split_op_builder.cc index 6372f3136123b..717d344982473 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/split_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/split_op_builder.cc @@ -56,7 +56,6 @@ Status SplitOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, return std::make_tuple(remainder, chunk_size); }; -#if defined(COREML_ENABLE_MLPROGRAM) if (model_builder.CreateMLProgram()) { using namespace CoreML::Specification::MILSpec; std::unique_ptr split_op = model_builder.CreateOperation(node, "split"); @@ -95,9 +94,7 @@ Status SplitOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, } model_builder.AddOperation(std::move(split_op)); - } else -#endif - { + } else { std::unique_ptr layer = model_builder.CreateNNLayer(node); auto* coreml_splitnd = layer->mutable_splitnd(); coreml_splitnd->set_axis(axis); diff --git a/onnxruntime/core/providers/coreml/builders/impl/squeeze_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/squeeze_op_builder.cc index a1b3a18265c70..81bef11906b74 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/squeeze_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/squeeze_op_builder.cc @@ -58,7 +58,6 @@ void SqueezeOpBuilder::AddInitializersToSkip(ModelBuilder& model_builder, const } } -#if defined(COREML_ENABLE_MLPROGRAM) void HandleX86ArchUnsqueezeScalarInput(ModelBuilder& model_builder, const Node& node, const logging::Logger& logger) { const auto& input_defs(node.InputDefs()); @@ -74,7 +73,6 @@ void HandleX86ArchUnsqueezeScalarInput(ModelBuilder& model_builder, AddOperationOutput(*op, *node.OutputDefs()[0]); model_builder.AddOperation(std::move(op)); } -#endif Status SqueezeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, @@ -83,7 +81,7 @@ Status SqueezeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, auto* coreml_squeeze = layer->mutable_squeeze(); TensorShapeVector axes; GetAxes(model_builder, node, axes); -#if defined(COREML_ENABLE_MLPROGRAM) + const auto& input_defs(node.InputDefs()); if (model_builder.CreateMLProgram()) { using namespace CoreML::Specification::MILSpec; @@ -105,9 +103,7 @@ Status SqueezeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, } AddOperationOutput(*op, *node.OutputDefs()[0]); model_builder.AddOperation(std::move(op)); - } else // NOLINT -#endif - { + } else { if (axes.empty()) { coreml_squeeze->set_squeezeall(true); } else { diff --git a/onnxruntime/core/providers/coreml/builders/impl/transpose_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/transpose_op_builder.cc index 831c4cf4d08ba..5bb7e4c11967a 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/transpose_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/transpose_op_builder.cc @@ -34,7 +34,6 @@ Status TransposeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, ORT_RETURN_IF_NOT(perm.size() == input_dims, "Perm and input should have same dimension"); } -#if defined(COREML_ENABLE_MLPROGRAM) if (model_builder.CreateMLProgram()) { using namespace CoreML::Specification::MILSpec; @@ -44,9 +43,7 @@ Status TransposeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, AddOperationOutput(*op, *node.OutputDefs()[0]); model_builder.AddOperation(std::move(op)); - } else -#endif // defined(COREML_ENABLE_MLPROGRAM) - { + } else { std::unique_ptr layer = model_builder.CreateNNLayer(node); *layer->mutable_transpose()->mutable_axes() = {perm.cbegin(), perm.cend()}; diff --git a/onnxruntime/core/providers/coreml/builders/impl/unary_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/unary_op_builder.cc index bc3cad004aec1..dd495894ab8bb 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/unary_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/unary_op_builder.cc @@ -25,7 +25,6 @@ Status UnaryOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const const auto& op_type(node.OpType()); const auto& input_defs(node.InputDefs()); -#if defined(COREML_ENABLE_MLPROGRAM) if (model_builder.CreateMLProgram()) { using namespace CoreML::Specification::MILSpec; @@ -58,9 +57,7 @@ Status UnaryOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const AddOperationOutput(*op, *node.OutputDefs()[0]); model_builder.AddOperation(std::move(op)); - } else // NOLINT -#endif // defined (COREML_ENABLE_MLPROGRAM) - { + } else { std::unique_ptr layer = model_builder.CreateNNLayer(node); if (op_type == "Sqrt") { diff --git a/onnxruntime/core/providers/coreml/builders/model_builder.cc b/onnxruntime/core/providers/coreml/builders/model_builder.cc index f8952301d59a9..3551f5759201e 100644 --- a/onnxruntime/core/providers/coreml/builders/model_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/model_builder.cc @@ -17,20 +17,17 @@ #include "core/providers/coreml/shape_utils.h" #include "core/optimizer/initializer.h" -#if defined(COREML_ENABLE_MLPROGRAM) // includes from coremltools-src in _deps #include "modelpackage/src/ModelPackage.hpp" #include "mlmodel/src/MILBlob/Blob/StorageWriter.hpp" using MILBlob::Blob::StorageWriter; -#endif - using namespace CoreML::Specification; namespace onnxruntime { namespace coreml { namespace { -#if defined(COREML_ENABLE_MLPROGRAM) + // Should the initializer be written to file or kept as an immediate value bool ShouldWriteInitializerToWeightsFile(const ONNX_NAMESPACE::TensorProto& tensor_proto) { // https://github.com/apple/coremltools/blob/dbb0094fd0cb936469e35320bf37e866ef7a1da4/coremltools/converters/mil/backend/mil/load.py#L51-L57 @@ -388,8 +385,6 @@ void CreateEmptyFile(const std::string& filename) { ORT_ENFORCE(file.is_open(), "Failed to open file ", filename); } -#endif // defined(COREML_ENABLE_MLPROGRAM) - std::string GetModelOutputPath(const CoreMLOptions& coreml_options, const GraphViewer& graph_viewer, const logging::Logger& logger) { @@ -479,7 +474,6 @@ ModelBuilder::ModelBuilder(const GraphViewer& graph_viewer, const logging::Logge } if (create_ml_program_) { -#if defined(COREML_ENABLE_MLPROGRAM) coreml_model_->set_specificationversion(CoreMLSpecVersion()); MILSpec::Program& mlprogram = *coreml_model_->mutable_mlprogram(); mlprogram.set_version(1); @@ -503,12 +497,6 @@ ModelBuilder::ModelBuilder(const GraphViewer& graph_viewer, const logging::Logge "CoreML Model Weights"); auto weights_info = mlpackage_->findItem(weights_id); weights_file_writer_ = std::make_unique(weights_info->path() + "/weight.bin"); -#else - // should never happen due to handling in coreml_execution_provider.cc - // throw here so all other code in this class can assume create_ml_program_ is only ever true in a build - // where ML Program support is enabled. - ORT_THROW("ML Program is not enabled in this build"); -#endif } else { // We support CorelML Specification Version 4 (Core ML 3) coreml_model_->set_specificationversion(4); @@ -561,7 +549,6 @@ void ModelBuilder::AddLayer(std::unique_ptr layer) { /* * ML Program related helpers */ -#if defined(COREML_ENABLE_MLPROGRAM) const std::string& ModelBuilder::GetSafeName(const std::string& name) { // Check the name is valid according to the MILSpec rules // `Identifiers, generally used for names and keys, must match the regular expression [A-Za-z\_][A-Za-z0-9\_@]*.` @@ -737,8 +724,6 @@ std::string_view ModelBuilder::AddConstantImpl(std::string_view op_type, std::st return AddTensorValueAsConstantOperation(op_type, value_type, std::move(input_value)); } -#endif // defined(COREML_ENABLE_MLPROGRAM) - /* * General implementation */ @@ -775,13 +760,10 @@ Status ModelBuilder::RegisterInitializers() { continue; } -#if defined(COREML_ENABLE_MLPROGRAM) if (create_ml_program_) { MILSpec::Value coreml_tensor = OnnxTensorToCoreMLTensor(tensor, *weights_file_writer_); ORT_IGNORE_RETURN_VALUE(AddConstantOperation(name, std::move(coreml_tensor))); - } else -#endif - { + } else { std::unique_ptr layer = std::make_unique(); layer->set_name(GetUniqueName("initializer_" + name)); @@ -915,7 +897,6 @@ Status ModelBuilder::RegisterModelInputOutput(const NodeArg& node_arg, bool is_i return Status::OK(); } -#if defined(COREML_ENABLE_MLPROGRAM) if (create_ml_program_) { if (is_input) { // the model inputs need to be wired up as args to the 'main' function. @@ -935,7 +916,6 @@ Status ModelBuilder::RegisterModelInputOutput(const NodeArg& node_arg, bool is_i *mlprogram_main_block_->mutable_outputs()->Add() = name; } } -#endif // defined(COREML_ENABLE_MLPROGRAM) return Status::OK(); } @@ -980,11 +960,9 @@ Status ModelBuilder::CreateModel() { ORT_RETURN_IF_ERROR(ProcessNodes()); ORT_RETURN_IF_ERROR(RegisterModelOutputs()); -#if defined(COREML_ENABLE_MLPROGRAM) if (create_ml_program_) { SanitizeNames(); } -#endif return Status::OK(); } @@ -992,7 +970,6 @@ Status ModelBuilder::CreateModel() { Status ModelBuilder::SaveModel() { std::string output_path = model_output_path_; -#if defined(COREML_ENABLE_MLPROGRAM) if (create_ml_program_) { // we need to jump through some hoops to get the model path the ML Program load wants. std::string tmp_model_path = model_output_path_ + "/tmp/model.mlmodel"; @@ -1003,7 +980,6 @@ Status ModelBuilder::SaveModel() { auto model_info = mlpackage_->findItem(model_id); output_path = model_info->path(); } -#endif // scope this so the stream is closed and flushed by the ofstream dtor { @@ -1012,19 +988,16 @@ Status ModelBuilder::SaveModel() { ORT_RETURN_IF_NOT(coreml_model_->SerializeToOstream(&stream), "Saving the CoreML model failed. Path=", output_path); } -#if defined(COREML_ENABLE_MLPROGRAM) // need to delete the ModelPackage instance for it to write out the manifest. clear out the other ML Program // related types as well. mlprogram_main_block_ = nullptr; mlpackage_.reset(); weights_file_writer_.reset(); -#endif return Status::OK(); } Status ModelBuilder::LoadModel(std::unique_ptr& model) { -#if defined(COREML_ENABLE_MLPROGRAM) if (create_ml_program_) { // we need to provide the sanitized names for model inputs/outputs so that info is captured. // the input/output matching when we execute the model from the CoreML EP is based on order, so the change @@ -1058,9 +1031,7 @@ Status ModelBuilder::LoadModel(std::unique_ptr& model) { std::move(scalar_outputs_), std::move(int64_outputs_), logger_, coreml_options_); - } else -#endif - { + } else { model = std::make_unique(model_output_path_, std::move(onnx_input_names_), std::move(onnx_output_names_), @@ -1073,7 +1044,6 @@ Status ModelBuilder::LoadModel(std::unique_ptr& model) { return model->LoadModel(); // load using CoreML API, including compilation } -#if defined(COREML_ENABLE_MLPROGRAM) std::string_view ModelBuilder::AddConstant(std::string_view op_type, std::string_view value_type, const ONNX_NAMESPACE::TensorProto& tensor, std::optional> shape) { @@ -1114,7 +1084,6 @@ std::string_view ModelBuilder::AddConstant(std::string_view op_type, std::string return ret; } -#endif // static Status ModelBuilder::Build(const GraphViewer& graph_viewer, const logging::Logger& logger, int32_t coreml_version, const CoreMLOptions& coreml_options, diff --git a/onnxruntime/core/providers/coreml/builders/model_builder.h b/onnxruntime/core/providers/coreml/builders/model_builder.h index 28c7dc42da581..f3012e8137e8c 100644 --- a/onnxruntime/core/providers/coreml/builders/model_builder.h +++ b/onnxruntime/core/providers/coreml/builders/model_builder.h @@ -9,7 +9,6 @@ #include "core/providers/coreml/model/model.h" #include "core/providers/coreml/coreml_options.h" -#if defined(COREML_ENABLE_MLPROGRAM) // coremltools classes namespace MPL { class ModelPackage; @@ -20,7 +19,6 @@ namespace Blob { class StorageWriter; } } // namespace MILBlob -#endif namespace onnxruntime { namespace coreml { @@ -58,11 +56,7 @@ class ModelBuilder { // Returns true if we are creating an ML Program bool CreateMLProgram() const { -#if defined(COREML_ENABLE_MLPROGRAM) return create_ml_program_; -#else - return false; -#endif } /* @@ -76,7 +70,6 @@ class ModelBuilder { // Add layer to the Core ML NeuralNetwork model void AddLayer(std::unique_ptr layer); -#if defined(COREML_ENABLE_MLPROGRAM) /* * MLProgram helpers */ @@ -147,7 +140,6 @@ class ModelBuilder { // add the operation to the main function void AddOperation(std::unique_ptr operation); -#endif /* * General helpers @@ -176,7 +168,6 @@ class ModelBuilder { const logging::Logger& Logger() const { return logger_; } private: -#if defined(COREML_ENABLE_MLPROGRAM) template std::string_view AddConstantImpl(std::string_view op_type, std::string_view value_type, gsl::span value, std::optional> shape = std::nullopt); @@ -190,7 +181,6 @@ class ModelBuilder { const std::string& AddConstantOperation(std::string_view name, COREML_SPEC::MILSpec::Value&& initializer); const std::string& AddTensorValueAsConstantOperation(std::string_view op_type, std::string_view value_type, COREML_SPEC::MILSpec::Value&& input_value); -#endif // Convert the ONNX model in graph_viewer_ to a CoreML::Specification::Model and serialize to disk. // We then load it using CoreML in order compile it. @@ -237,7 +227,6 @@ class ModelBuilder { uint32_t name_token_{0}; std::unordered_set unique_names_; -#if defined(COREML_ENABLE_MLPROGRAM) // mlprogram_main_ is the main block of the CoreML ML Program. // It is set in CreateModel to the CoreML Model.mlprogram.functions['main'].block_specializations['CoreML'] // entry we create. @@ -254,7 +243,6 @@ class ModelBuilder { // This means an op builder author doesn't need to be aware of the renaming. // https://github.com/apple/coremltools/blob/8b37641f243b1a3e81452feea311c6e30dcc9287/coremltools/converters/mil/mil/passes/defs/preprocess.py#L146-L149 std::unordered_map values_to_rename_; -#endif }; } // namespace coreml diff --git a/onnxruntime/core/providers/coreml/coreml_execution_provider.cc b/onnxruntime/core/providers/coreml/coreml_execution_provider.cc index 3fa3868267c9b..cc7beed6bb298 100644 --- a/onnxruntime/core/providers/coreml/coreml_execution_provider.cc +++ b/onnxruntime/core/providers/coreml/coreml_execution_provider.cc @@ -39,6 +39,7 @@ CoreMLExecutionProvider::~CoreMLExecutionProvider() {} std::vector> CoreMLExecutionProvider::GetCapability(const onnxruntime::GraphViewer& graph_viewer, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const { std::vector> result; diff --git a/onnxruntime/core/providers/coreml/coreml_execution_provider.h b/onnxruntime/core/providers/coreml/coreml_execution_provider.h index 0609bf6af726d..574ae1fc0106b 100644 --- a/onnxruntime/core/providers/coreml/coreml_execution_provider.h +++ b/onnxruntime/core/providers/coreml/coreml_execution_provider.h @@ -20,6 +20,7 @@ class CoreMLExecutionProvider : public IExecutionProvider { std::vector> GetCapability(const onnxruntime::GraphViewer& graph_viewer, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* resource_accountant) const override; #if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) diff --git a/onnxruntime/core/providers/coreml/coreml_options.cc b/onnxruntime/core/providers/coreml/coreml_options.cc index 14ae55de9266b..c441a2eff56e0 100644 --- a/onnxruntime/core/providers/coreml/coreml_options.cc +++ b/onnxruntime/core/providers/coreml/coreml_options.cc @@ -15,18 +15,6 @@ CoreMLOptions::CoreMLOptions(uint32_t coreml_flags) { create_mlprogram_ = (coreml_flags & COREML_FLAG_CREATE_MLPROGRAM) != 0; enable_on_subgraph_ = (coreml_flags & COREML_FLAG_ENABLE_ON_SUBGRAPH) != 0; -#if defined(COREML_ENABLE_MLPROGRAM) - if (coreml::util::CoreMLVersion() < MINIMUM_COREML_MLPROGRAM_VERSION && create_mlprogram_ != 0) { - LOGS_DEFAULT(WARNING) << "ML Program is not supported on this OS version. Falling back to NeuralNetwork."; - create_mlprogram_ = false; - } -#else - if (create_mlprogram_ != 0) { - LOGS_DEFAULT(WARNING) << "ML Program is not supported in this build. Falling back to NeuralNetwork."; - create_mlprogram_ = false; - } -#endif - compute_units_ = 0; // 0 for all if (coreml_flags & COREML_FLAG_USE_CPU_ONLY) { diff --git a/onnxruntime/core/providers/coreml/model/host_utils.h b/onnxruntime/core/providers/coreml/model/host_utils.h index 145c64e5320d3..f654b4d5701b9 100644 --- a/onnxruntime/core/providers/coreml/model/host_utils.h +++ b/onnxruntime/core/providers/coreml/model/host_utils.h @@ -43,7 +43,13 @@ #define API_AVAILABLE_COREML7 API_AVAILABLE(macos(14), ios(17)) #define API_AVAILABLE_COREML8 API_AVAILABLE(macos(15), ios(18)) -// @available is used in implementation code +// The previous macros are used in header files to declare the availability of the APIs. +// The following macros are used in build time checks to determine if the APIs are available. +#define CAN_BUILD_COREML8_OR_LATER (__MAC_OS_X_VERSION_MAX_ALLOWED >= 150000 && __IPHONE_OS_VERSION_MAX_ALLOWED >= 180000) +#define CAN_BUILD_COREML7_OR_LATER (__MAC_OS_X_VERSION_MAX_ALLOWED >= 140000 && __IPHONE_OS_VERSION_MAX_ALLOWED >= 170000) +#define CAN_BUILD_COREML6_OR_LATER (__MAC_OS_X_VERSION_MAX_ALLOWED >= 130000 && __IPHONE_OS_VERSION_MAX_ALLOWED >= 160000) + +// @available is used in implementation code to check the availability of the APIs at runtime. // Base required OS to run CoreML Specification Version 4 (Core ML 3) #define HAS_COREML3_OR_LATER @available(macOS 10.15, iOS 13, *) #define HAS_COREML4_OR_LATER @available(macOS 11, iOS 14, *) @@ -54,8 +60,7 @@ #endif -#define MINIMUM_COREML_VERSION 3 // first version we support -#define MINIMUM_COREML_MLPROGRAM_VERSION 5 // first version where ML Program was available +#define MINIMUM_COREML_VERSION 5 // first version we support namespace onnxruntime { namespace coreml { diff --git a/onnxruntime/core/providers/coreml/model/model.mm b/onnxruntime/core/providers/coreml/model/model.mm index 5211b89ec17c6..71664021ea2fb 100644 --- a/onnxruntime/core/providers/coreml/model/model.mm +++ b/onnxruntime/core/providers/coreml/model/model.mm @@ -363,13 +363,12 @@ void ProfileComputePlan(NSURL* compileUrl, MLModelConfiguration* config) { #endif } -#if __has_include() +#if __has_include() && CAN_BUILD_COREML8_OR_LATER #define HAS_COREMLOPTIMIZATIONHINT 1 #else #define HAS_COREMLOPTIMIZATIONHINT 0 #endif -API_AVAILABLE_COREML8 void ConfigureOptimizationHints(MLModelConfiguration* config, const CoreMLOptions& coreml_options) { #if HAS_COREMLOPTIMIZATIONHINT MLOptimizationHints* optimizationHints = [[MLOptimizationHints alloc] init]; diff --git a/onnxruntime/core/providers/cpu/controlflow/loop.cc b/onnxruntime/core/providers/cpu/controlflow/loop.cc index c65dd2a04bf55..b33b1f189594b 100644 --- a/onnxruntime/core/providers/cpu/controlflow/loop.cc +++ b/onnxruntime/core/providers/cpu/controlflow/loop.cc @@ -244,7 +244,7 @@ static Status ConcatenateCpuOutput(void* /*stream*/, // we can't easily use a C++ template for the tensor element type, // so use a span for some protection but work in bytes - gsl::span output_span = gsl::make_span(static_cast(output), + gsl::span output_span = gsl::make_span(static_cast(output), output_size_in_bytes); for (size_t i = 0, num_iterations = per_iteration_output.size(); i < num_iterations; ++i) { @@ -257,7 +257,7 @@ static Status ConcatenateCpuOutput(void* /*stream*/, " Expected:", per_iteration_shape, " Got:", iteration_data.Shape()); } - auto src = gsl::make_span(static_cast(iteration_data.DataRaw()), + auto src = gsl::make_span(static_cast(iteration_data.DataRaw()), bytes_per_iteration); auto dst = output_span.subspan(i * bytes_per_iteration, bytes_per_iteration); gsl::copy(src, dst); diff --git a/onnxruntime/core/providers/cpu/quantization/conv_integer.cc b/onnxruntime/core/providers/cpu/quantization/conv_integer.cc index 03b39e19ed748..f3c6b18f8e753 100644 --- a/onnxruntime/core/providers/cpu/quantization/conv_integer.cc +++ b/onnxruntime/core/providers/cpu/quantization/conv_integer.cc @@ -34,17 +34,18 @@ ONNX_OPERATOR_KERNEL_EX( ConvInteger); Status ConvInteger::Compute(OpKernelContext* context) const { - size_t num_inputs = OpKernel::Node().InputDefs().size(); + const auto input_defs = Node().InputDefs(); + size_t num_inputs = input_defs.size(); const auto* X = context->Input(0); const auto* W = context->Input(1); uint8_t input_offset = 0; uint8_t filter_offset = 0; - if (num_inputs >= 3) { + if (num_inputs >= 3 && input_defs[2]->Exists()) { const auto* X_Zero_Point = context->Input(2); ORT_ENFORCE(IsScalarOr1ElementVector(X_Zero_Point), "Must be a scalar or 1D tensor or size 1."); input_offset = *(X_Zero_Point->Data()); } - if (num_inputs >= 4) { + if (num_inputs >= 4 && input_defs[3]->Exists()) { const auto* W_Zero_Point = context->Input(3); ORT_ENFORCE(IsScalarOr1ElementVector(W_Zero_Point), "Non per-tensor quantization is not supported now."); filter_offset = *(W_Zero_Point->Data()); diff --git a/onnxruntime/core/providers/cpu/tensor/cast_op.cc b/onnxruntime/core/providers/cpu/tensor/cast_op.cc index 35f3b12aeba35..639a49cb43a4f 100644 --- a/onnxruntime/core/providers/cpu/tensor/cast_op.cc +++ b/onnxruntime/core/providers/cpu/tensor/cast_op.cc @@ -254,11 +254,32 @@ struct TensorCasterNoSat { // tensor MLFloat16 -> float template <> struct TensorCaster { - void Cast(const OpKernelContext&, const TensorShape& shape, const Tensor& in, Tensor& out) const { + void Cast(const OpKernelContext& ctx, const TensorShape& shape, const Tensor& in, Tensor& out) const { auto out_data = out.MutableData(); auto in_data = in.Data(); const size_t shape_size = narrow(shape.Size()); - MlasConvertHalfToFloatBuffer(in_data, out_data, shape_size); + + // Check if the tensor is long enough to use threads + if (shape_size <= 128000) { + MlasConvertHalfToFloatBuffer(in_data, out_data, shape_size); + return; + } + // Calculate the number of compute cyles per implementation + auto cpu_info = CPUIDInfo::GetCPUIDInfo(); + double num_compute_cycles; + if (cpu_info.HasSSE3()) { + num_compute_cycles = static_cast(shape_size >> 1); + } else if (cpu_info.HasAVX2()) { + num_compute_cycles = static_cast(shape_size >> 2); + } else { + num_compute_cycles = static_cast(shape_size * 10); + } + + concurrency::ThreadPool::TryParallelFor(ctx.GetOperatorThreadPool(), shape_size, + {shape_size * 2.f, shape_size * 4.f, num_compute_cycles}, + [in_data, out_data](std::ptrdiff_t first_span, std::ptrdiff_t last_span) { + MlasConvertHalfToFloatBuffer(in_data + first_span, out_data + first_span, static_cast(last_span - first_span)); + }); } }; diff --git a/onnxruntime/core/providers/cuda/controlflow/loop.cc b/onnxruntime/core/providers/cuda/controlflow/loop.cc index 3295b73a800c9..d66de7c74e647 100644 --- a/onnxruntime/core/providers/cuda/controlflow/loop.cc +++ b/onnxruntime/core/providers/cuda/controlflow/loop.cc @@ -84,10 +84,10 @@ static Status ConcatenateGpuOutput(void* stream, std::vector& per_iter CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(cur_output, iteration_data.DataRaw(), bytes_per_iteration, cudaMemcpyDeviceToDevice, static_cast(stream))); - cur_output = static_cast((static_cast(cur_output) + bytes_per_iteration)); + cur_output = static_cast((static_cast(cur_output) + bytes_per_iteration)); } - ORT_ENFORCE(static_cast(cur_output) - static_cast(output) == output_size_in_bytes, + ORT_ENFORCE(static_cast(cur_output) - static_cast(output) == output_size_in_bytes, "Concatenation did not fill output buffer as expected."); return Status::OK(); diff --git a/onnxruntime/core/providers/cuda/cu_inc/common.cuh b/onnxruntime/core/providers/cuda/cu_inc/common.cuh index 55935a9eae86d..2d2551a156099 100644 --- a/onnxruntime/core/providers/cuda/cu_inc/common.cuh +++ b/onnxruntime/core/providers/cuda/cu_inc/common.cuh @@ -441,6 +441,9 @@ __device__ __inline__ T _Sign(T a) { return _Signum(a, std::is_signed()); } template <> __device__ __inline__ half _Sign(half a) { return _Signum(a, std::true_type()); } +template <> +__device__ __inline__ BFloat16 _Sign(BFloat16 a) { return _Signum(static_cast(a), std::true_type()); } + template __device__ __inline__ T _Normcdf(T a); diff --git a/onnxruntime/core/providers/cuda/cuda_execution_provider.cc b/onnxruntime/core/providers/cuda/cuda_execution_provider.cc index b675c08e5f804..635eb67bbedd0 100644 --- a/onnxruntime/core/providers/cuda/cuda_execution_provider.cc +++ b/onnxruntime/core/providers/cuda/cuda_execution_provider.cc @@ -420,8 +420,6 @@ Status CUDAExecutionProvider::Sync() const { } Status CUDAExecutionProvider::OnRunStart(const onnxruntime::RunOptions& run_options) { - // always set CUDA device when session::Run() in case it runs in a worker thread - CUDA_RETURN_IF_ERROR(cudaSetDevice(GetDeviceId())); CudaGraphAnnotation_t cuda_graph_annotation_id = GetPerThreadContext().GetCudaGraphAnnotationId(run_options); if (IsGraphCaptureEnabled() && !GetPerThreadContext().IsGraphCaptured(cuda_graph_annotation_id) && GetPerThreadContext().IsGraphCaptureAllowed(cuda_graph_annotation_id)) { @@ -1013,6 +1011,7 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, float, Abs); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, double, Abs); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, MLFloat16, Abs); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, BFloat16, Abs); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, int8_t, Neg); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, int16_t, Neg); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, int32_t, Neg); @@ -1188,6 +1187,7 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, float, Sign); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, double, Sign); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, MLFloat16, Sign); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, BFloat16, Sign); class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 13, BFloat16, Add); class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 13, BFloat16, Sub); @@ -1996,6 +1996,7 @@ static Status RegisterCudaKernels(KernelRegistry& kernel_registry) { BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, @@ -2169,6 +2170,7 @@ static Status RegisterCudaKernels(KernelRegistry& kernel_registry) { BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, @@ -2660,6 +2662,7 @@ std::unique_ptr CUDAExecutionProvider::GetDataTransf std::vector> CUDAExecutionProvider::GetCapability(const onnxruntime::GraphViewer& graph, const IKernelLookup& kernel_lookup, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* resource_accountant) const { std::vector> result; const logging::Logger& logger = *GetLogger(); diff --git a/onnxruntime/core/providers/cuda/cuda_execution_provider.h b/onnxruntime/core/providers/cuda/cuda_execution_provider.h index 79a48e7cb89e1..a75e81f1f0c6d 100644 --- a/onnxruntime/core/providers/cuda/cuda_execution_provider.h +++ b/onnxruntime/core/providers/cuda/cuda_execution_provider.h @@ -73,6 +73,7 @@ class CUDAExecutionProvider : public IExecutionProvider { std::vector> GetCapability( const onnxruntime::GraphViewer& graph, const IKernelLookup& kernel_lookup, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* resource_accountant) const override; int GetDeviceId() const override { return info_.device_id; } diff --git a/onnxruntime/core/providers/cuda/cuda_stream_handle.cc b/onnxruntime/core/providers/cuda/cuda_stream_handle.cc index e9b159516dad9..51fd2c67b7478 100644 --- a/onnxruntime/core/providers/cuda/cuda_stream_handle.cc +++ b/onnxruntime/core/providers/cuda/cuda_stream_handle.cc @@ -266,6 +266,7 @@ void RegisterCudaStreamHandles(IStreamCommandHandleRegistry& stream_handle_regis ep_info](const OrtDevice& device) { return std::make_unique(external_stream, device, cpu_allocator, release_cpu_buffer_on_cuda_stream, false, external_cudnn_handle, external_cublas_handle, ep_info); }); + stream_handle_registry.RegisterSetDeviceFn(device_type, [](OrtDevice::DeviceId id) { CUDA_CALL_THROW(cudaSetDevice(id)); }); } } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/math/unary_elementwise_ops.cc b/onnxruntime/core/providers/cuda/math/unary_elementwise_ops.cc index fb03b4326c4e8..86a1b0f5b6102 100644 --- a/onnxruntime/core/providers/cuda/math/unary_elementwise_ops.cc +++ b/onnxruntime/core/providers/cuda/math/unary_elementwise_ops.cc @@ -213,19 +213,19 @@ Status IsNaN::ComputeInternal(OpKernelContext* context) const { UNARY_OP_TYPED(name, ver, float) \ UNARY_OP_TYPED(name, ver, double) -#define UNARY_OP_CSILHFD(name, ver) \ +#define UNARY_OP_CSILHFDX(name, ver) \ UNARY_OP_TYPED(name, ver, int8_t) \ UNARY_OP_TYPED(name, ver, int16_t) \ UNARY_OP_TYPED(name, ver, int32_t) \ UNARY_OP_TYPED(name, ver, int64_t) \ UNARY_OP_HFDX(name, ver) -#define UNARY_OP_BWUZCSILHFD(name, ver) \ - UNARY_OP_TYPED(name, ver, uint8_t) \ - UNARY_OP_TYPED(name, ver, uint16_t) \ - UNARY_OP_TYPED(name, ver, uint32_t) \ - UNARY_OP_TYPED(name, ver, uint64_t) \ - UNARY_OP_CSILHFD(name, ver) +#define UNARY_OP_BWUZCSILHFDX(name, ver) \ + UNARY_OP_TYPED(name, ver, uint8_t) \ + UNARY_OP_TYPED(name, ver, uint16_t) \ + UNARY_OP_TYPED(name, ver, uint32_t) \ + UNARY_OP_TYPED(name, ver, uint64_t) \ + UNARY_OP_CSILHFDX(name, ver) UNARY_OP_VERSIONED_BWUZCSILHFD(Abs, 6, 12) UNARY_OP_VERSIONED_CSILHFD(Neg, 6, 12) @@ -237,8 +237,8 @@ UNARY_OP_VERSIONED_HFD(Log, 6, 12) UNARY_OP_VERSIONED_HFD(Exp, 6, 12) UNARY_OP_VERSIONED_HFD(Erf, 9, 12) -UNARY_OP_BWUZCSILHFD(Abs, 13) -UNARY_OP_CSILHFD(Neg, 13) +UNARY_OP_BWUZCSILHFDX(Abs, 13) +UNARY_OP_CSILHFDX(Neg, 13) UNARY_OP_HFD(Floor, 13) UNARY_OP_HFD(Ceil, 13) UNARY_OP_HFD(Reciprocal, 13) @@ -246,7 +246,7 @@ UNARY_OP_HFDX(Sqrt, 13) UNARY_OP_HFD(Log, 13) UNARY_OP_HFDX(Exp, 13) UNARY_OP_HFDX(Erf, 13) -UNARY_OP_BWUZCSILHFD(Sign, 13) +UNARY_OP_BWUZCSILHFDX(Sign, 13) UNARY_LOGICALOP_NOT_TYPED(1, bool) UNARY_OP_HFD(Round, 11) diff --git a/onnxruntime/core/providers/cuda/tensor/upsample.cc b/onnxruntime/core/providers/cuda/tensor/upsample.cc index cbf745d3c7b4f..a38fe1efad540 100644 --- a/onnxruntime/core/providers/cuda/tensor/upsample.cc +++ b/onnxruntime/core/providers/cuda/tensor/upsample.cc @@ -290,16 +290,16 @@ Status Upsample::BaseCompute(OpKernelContext* context, scales_div[i] = fast_divmod(gsl::narrow_cast(ceil(scales[i]))); } - UpampleImpl(Stream(context), - mode_, - rank, - (UpsampleMode::LINEAR == mode_) ? (rank == 2 ? X_dims[0] : X_dims[2]) : 0, - input_strides, - output_div_pitches, - scales_div, - reinterpret_cast(X->Data()), - reinterpret_cast(Y->MutableData()), - output_count); + UpsampleImpl(Stream(context), + mode_, + rank, + (UpsampleMode::LINEAR == mode_) ? (rank == 2 ? X_dims[0] : X_dims[2]) : 0, + input_strides, + output_div_pitches, + scales_div, + reinterpret_cast(X->Data()), + reinterpret_cast(Y->MutableData()), + output_count); } return Status::OK(); diff --git a/onnxruntime/core/providers/cuda/tensor/upsample_impl.cu b/onnxruntime/core/providers/cuda/tensor/upsample_impl.cu index d1c2ae6332994..24aeada559979 100644 --- a/onnxruntime/core/providers/cuda/tensor/upsample_impl.cu +++ b/onnxruntime/core/providers/cuda/tensor/upsample_impl.cu @@ -8,12 +8,12 @@ namespace onnxruntime { namespace cuda { template -__global__ void _UpampleNearestKernel(const TArray input_pitches, - const TArray output_div_pitches, - const TArray scales_div, - const T* __restrict__ input_data, - T* __restrict__ output_data, - const size_t N) { +__global__ void _UpsampleNearestKernel(const TArray input_pitches, + const TArray output_div_pitches, + const TArray scales_div, + const T* __restrict__ input_data, + T* __restrict__ output_data, + const size_t N) { CALCULATE_ELEMENTWISE_INDEX_OR_EXIT(id, N); CUDA_LONG input_index = 0; CUDA_LONG output_index = id; @@ -36,13 +36,13 @@ __global__ void _UpampleNearestKernel(const TArray input_pitches, // This is the common use-case where the 4-D input (batched multi-channel images) // is usually of shape [N, C, H, W] and the scales are [1.0, 1.0, height_scale, width_scale] template -__global__ void _UpampleBilinear4DInputKernel(const int64_t input_dim2, - const TArray input_pitches, - const TArray output_div_pitches, - const TArray scales_div, - const T* __restrict__ input_data, - T* __restrict__ output_data, - const size_t N) { +__global__ void _UpsampleBilinear4DInputKernel(const int64_t input_dim2, + const TArray input_pitches, + const TArray output_div_pitches, + const TArray scales_div, + const T* __restrict__ input_data, + T* __restrict__ output_data, + const size_t N) { CALCULATE_ELEMENTWISE_INDEX_OR_EXIT(id, N); CUDA_LONG input_index = 0; @@ -95,13 +95,13 @@ __global__ void _UpampleBilinear4DInputKernel(const int64_t input_dim2, // The following method supports a 2-D input in 'Linear mode' template -__global__ void _UpampleBilinear2DInputKernel(const int64_t input_dim0, - const TArray input_pitches, - const TArray output_div_pitches, - const TArray scales_div, - const T* __restrict__ input_data, - T* __restrict__ output_data, - const size_t N) { +__global__ void _UpsampleBilinear2DInputKernel(const int64_t input_dim0, + const TArray input_pitches, + const TArray output_div_pitches, + const TArray scales_div, + const T* __restrict__ input_data, + T* __restrict__ output_data, + const size_t N) { CALCULATE_ELEMENTWISE_INDEX_OR_EXIT(id, N); CUDA_LONG input_index = 0; @@ -147,32 +147,32 @@ __global__ void _UpampleBilinear2DInputKernel(const int64_t input_dim0, } template -void UpampleImpl(cudaStream_t stream, - const onnxruntime::UpsampleMode upsample_mode, - const size_t rank, - const int64_t input_dim2, - const TArray& input_pitches, - const TArray& output_div_pitches, - const TArray& scales_div, - const T* input_data, - T* output_data, - const size_t N) { +void UpsampleImpl(cudaStream_t stream, + const onnxruntime::UpsampleMode upsample_mode, + const size_t rank, + const int64_t input_dim2, + const TArray& input_pitches, + const TArray& output_div_pitches, + const TArray& scales_div, + const T* input_data, + T* output_data, + const size_t N) { int blocksPerGrid = (int)(ceil(static_cast(N) / GridDim::maxThreadsPerBlock)); if (onnxruntime::UpsampleMode::NN == upsample_mode) { if (rank == 4) { - _UpampleNearestKernel<<>>( + _UpsampleNearestKernel<<>>( input_pitches, output_div_pitches, scales_div, input_data, output_data, N); } else if (rank == 3) { - _UpampleNearestKernel<<>>( + _UpsampleNearestKernel<<>>( input_pitches, output_div_pitches, scales_div, input_data, output_data, N); } else if (rank == 2) { - _UpampleNearestKernel<<>>( + _UpsampleNearestKernel<<>>( input_pitches, output_div_pitches, scales_div, input_data, output_data, N); } else if (rank == 1) { - _UpampleNearestKernel<<>>( + _UpsampleNearestKernel<<>>( input_pitches, output_div_pitches, scales_div, input_data, output_data, N); } else { @@ -180,11 +180,11 @@ void UpampleImpl(cudaStream_t stream, } } else if (onnxruntime::UpsampleMode::LINEAR == upsample_mode) { if (rank == 4) { - _UpampleBilinear4DInputKernel<<>>( + _UpsampleBilinear4DInputKernel<<>>( input_dim2, input_pitches, output_div_pitches, scales_div, input_data, output_data, N); } else if (rank == 2) { - _UpampleBilinear2DInputKernel<<>>( + _UpsampleBilinear2DInputKernel<<>>( input_dim2, input_pitches, output_div_pitches, scales_div, input_data, output_data, N); } else { @@ -197,17 +197,17 @@ void UpampleImpl(cudaStream_t stream, } } -#define SPECIALIZED_IMPL(T) \ - template void UpampleImpl(cudaStream_t stream, \ - const onnxruntime::UpsampleMode upsample_mode, \ - const size_t rank, \ - const int64_t input_dim2, \ - const TArray& input_pitches, \ - const TArray& output_div_pitches, \ - const TArray& scales_div, \ - const T* input_data, \ - T* output_data, \ - const size_t N); +#define SPECIALIZED_IMPL(T) \ + template void UpsampleImpl(cudaStream_t stream, \ + const onnxruntime::UpsampleMode upsample_mode, \ + const size_t rank, \ + const int64_t input_dim2, \ + const TArray& input_pitches, \ + const TArray& output_div_pitches, \ + const TArray& scales_div, \ + const T* input_data, \ + T* output_data, \ + const size_t N); SPECIALIZED_IMPL(float) SPECIALIZED_IMPL(double) diff --git a/onnxruntime/core/providers/cuda/tensor/upsample_impl.h b/onnxruntime/core/providers/cuda/tensor/upsample_impl.h index 250ec6b272e34..fb47ad8301615 100644 --- a/onnxruntime/core/providers/cuda/tensor/upsample_impl.h +++ b/onnxruntime/core/providers/cuda/tensor/upsample_impl.h @@ -11,16 +11,16 @@ namespace onnxruntime { namespace cuda { template -void UpampleImpl(cudaStream_t stream, - const onnxruntime::UpsampleMode upsample_mode, - const size_t rank, - const int64_t input_dim2, - const TArray& input_pitches, - const TArray& output_div_pitches, - const TArray& scales_div, - const T* input_data, - T* output_data, - const size_t N); +void UpsampleImpl(cudaStream_t stream, + const onnxruntime::UpsampleMode upsample_mode, + const size_t rank, + const int64_t input_dim2, + const TArray& input_pitches, + const TArray& output_div_pitches, + const TArray& scales_div, + const T* input_data, + T* output_data, + const size_t N); } // namespace cuda } // namespace onnxruntime diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.cpp index 9d23b8b950272..868b2103586f9 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.cpp @@ -93,12 +93,13 @@ namespace Dml ExecutionProvider::GetCapability( const onnxruntime::GraphViewer& graph, const onnxruntime::IExecutionProvider::IKernelLookup& kernel_lookup, + const onnxruntime::GraphOptimizerRegistry& graph_optimizer_registry, onnxruntime::IResourceAccountant* resource_accountant) const { #ifdef ENABLE_GRAPH_COMPILATION - return m_impl->GetCapability(graph, kernel_lookup, resource_accountant, *GetLogger()); + return m_impl->GetCapability(graph, kernel_lookup, graph_optimizer_registry, resource_accountant, *GetLogger()); #else - return onnxruntime::IExecutionProvider::GetCapability(graph, kernel_lookup, resource_accountant); + return onnxruntime::IExecutionProvider::GetCapability(graph, kernel_lookup, graph_optimizer_registry, resource_accountant); #endif } @@ -878,6 +879,7 @@ namespace Dml ExecutionProviderImpl::GetCapability( const onnxruntime::GraphViewer& graph, const onnxruntime::IExecutionProvider::IKernelLookup& kernel_lookup, + const onnxruntime::GraphOptimizerRegistry& /* graph_optimizer_registry */, onnxruntime::IResourceAccountant*, const onnxruntime::logging::Logger& logger) const { uint32_t deviceDataTypeMask = GetSupportedDeviceDataTypeMask(); // Each bit corresponds to each DML_TENSOR_DATA_TYPE. diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.h index 7f420f8850001..aa3d8b0b4a409 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.h @@ -13,6 +13,7 @@ namespace onnxruntime { class IResourceAccountant; +class GraphOptimizerRegistry; } namespace WRL { @@ -93,6 +94,7 @@ namespace Dml GetCapability( const onnxruntime::GraphViewer& graph, const onnxruntime::IExecutionProvider::IKernelLookup& kernel_lookup, + const onnxruntime::GraphOptimizerRegistry& graph_optimizer_registry, onnxruntime::IResourceAccountant* resource_accountant, const onnxruntime::logging::Logger& logger) const; @@ -288,6 +290,7 @@ namespace Dml std::vector> GetCapability(const onnxruntime::GraphViewer& graph, const onnxruntime::IExecutionProvider::IKernelLookup& kernel_lookup, + const onnxruntime::GraphOptimizerRegistry& /* graph_optimizer_registry */, onnxruntime::IResourceAccountant* resource_accountant) const final override; onnxruntime::common::Status OnSessionInitializationEnd() override diff --git a/onnxruntime/core/providers/dnnl/dnnl_execution_provider.cc b/onnxruntime/core/providers/dnnl/dnnl_execution_provider.cc index 4da82b351f1d6..d0e5b0b1588ef 100644 --- a/onnxruntime/core/providers/dnnl/dnnl_execution_provider.cc +++ b/onnxruntime/core/providers/dnnl/dnnl_execution_provider.cc @@ -147,6 +147,7 @@ std::vector> DnnlExecutionProvider::GetSupportedNodes(con std::vector> DnnlExecutionProvider::GetCapability( const GraphViewer& graph_viewer, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const { // follow from coreml ep's Getcapability diff --git a/onnxruntime/core/providers/dnnl/dnnl_execution_provider.h b/onnxruntime/core/providers/dnnl/dnnl_execution_provider.h index bde18e139f2a3..8f951efef2a94 100644 --- a/onnxruntime/core/providers/dnnl/dnnl_execution_provider.h +++ b/onnxruntime/core/providers/dnnl/dnnl_execution_provider.h @@ -25,6 +25,7 @@ class DnnlExecutionProvider : public IExecutionProvider { std::vector> GetCapability(const onnxruntime::GraphViewer& graph, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, onnxruntime::IResourceAccountant* /* resource_accountant */) const override; common::Status Compile(const std::vector& fused_nodes_and_graphs, diff --git a/onnxruntime/core/providers/js/js_execution_provider.cc b/onnxruntime/core/providers/js/js_execution_provider.cc index 9d00436150286..d8e24ff1f5053 100644 --- a/onnxruntime/core/providers/js/js_execution_provider.cc +++ b/onnxruntime/core/providers/js/js_execution_provider.cc @@ -791,6 +791,7 @@ std::vector JsExecutionProvider::CreatePreferredAllocators() { std::vector> JsExecutionProvider::GetCapability( const onnxruntime::GraphViewer& graph, const IKernelLookup& kernel_lookup, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const { InlinedVector candidates; // `tenative_candidates` is a subset of `candidates`. diff --git a/onnxruntime/core/providers/js/js_execution_provider.h b/onnxruntime/core/providers/js/js_execution_provider.h index 4bead50fc782e..c87303209c689 100644 --- a/onnxruntime/core/providers/js/js_execution_provider.h +++ b/onnxruntime/core/providers/js/js_execution_provider.h @@ -45,6 +45,7 @@ class JsExecutionProvider : public IExecutionProvider { std::vector> GetCapability( const onnxruntime::GraphViewer& graph_viewer, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const override; std::shared_ptr GetKernelRegistry() const override; diff --git a/onnxruntime/core/providers/migraphx/migraphx_allocator.cc b/onnxruntime/core/providers/migraphx/migraphx_allocator.cc index 3d9ae2bf7e6ff..cf9f44f4cd8f0 100644 --- a/onnxruntime/core/providers/migraphx/migraphx_allocator.cc +++ b/onnxruntime/core/providers/migraphx/migraphx_allocator.cc @@ -68,7 +68,7 @@ void* MIGraphXExternalAllocator::Reserve(size_t size) { return p; } -void* HIPPinnedAllocator::Alloc(size_t size) { +void* MIGraphXPinnedAllocator::Alloc(size_t size) { void* p = nullptr; if (size > 0) { HIP_CALL_THROW(hipHostMalloc((void**)&p, size)); @@ -76,7 +76,7 @@ void* HIPPinnedAllocator::Alloc(size_t size) { return p; } -void HIPPinnedAllocator::Free(void* p) { +void MIGraphXPinnedAllocator::Free(void* p) { HIP_CALL_THROW(hipHostFree(p)); } diff --git a/onnxruntime/core/providers/migraphx/migraphx_allocator.h b/onnxruntime/core/providers/migraphx/migraphx_allocator.h index c8c935eba44ab..2a84445897391 100644 --- a/onnxruntime/core/providers/migraphx/migraphx_allocator.h +++ b/onnxruntime/core/providers/migraphx/migraphx_allocator.h @@ -49,17 +49,16 @@ class MIGraphXExternalAllocator : public MIGraphXAllocator { std::unordered_set reserved_; }; -// TODO: add a default constructor -class HIPPinnedAllocator : public IAllocator { +class MIGraphXPinnedAllocator final : public IAllocator { public: - HIPPinnedAllocator(int device_id, const char* name) + MIGraphXPinnedAllocator(const int device_id, const char* name) : IAllocator( - OrtMemoryInfo(name, OrtAllocatorType::OrtDeviceAllocator, + OrtMemoryInfo(name, OrtDeviceAllocator, OrtDevice(OrtDevice::CPU, OrtDevice::MemType::HIP_PINNED, static_cast(device_id)), device_id, OrtMemTypeCPUOutput)) {} - virtual void* Alloc(size_t size) override; - virtual void Free(void* p) override; + void* Alloc(size_t size) override; + void Free(void* p) override; }; } // namespace onnxruntime diff --git a/onnxruntime/core/providers/migraphx/migraphx_execution_provider.cc b/onnxruntime/core/providers/migraphx/migraphx_execution_provider.cc index 1558d22137c05..9a694b03387ae 100644 --- a/onnxruntime/core/providers/migraphx/migraphx_execution_provider.cc +++ b/onnxruntime/core/providers/migraphx/migraphx_execution_provider.cc @@ -993,6 +993,7 @@ GetPartitionedSubgraphs(const std::vector& topological_order, std::vector> MIGraphXExecutionProvider::GetCapability(const onnxruntime::GraphViewer& graph_viewer, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const { std::vector> result; auto model = graph_viewer.CreateModel(*GetLogger()); diff --git a/onnxruntime/core/providers/migraphx/migraphx_execution_provider.h b/onnxruntime/core/providers/migraphx/migraphx_execution_provider.h index d6af991f9b77e..7c89b5ec544a1 100644 --- a/onnxruntime/core/providers/migraphx/migraphx_execution_provider.h +++ b/onnxruntime/core/providers/migraphx/migraphx_execution_provider.h @@ -69,6 +69,7 @@ class MIGraphXExecutionProvider : public IExecutionProvider { std::vector> GetCapability(const onnxruntime::GraphViewer& graph_viewer, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const override; common::Status Compile(const std::vector& fused_nodes, diff --git a/onnxruntime/core/providers/migraphx/migraphx_provider_factory.cc b/onnxruntime/core/providers/migraphx/migraphx_provider_factory.cc index 7b192b657b7cc..2904c17bb4aa0 100644 --- a/onnxruntime/core/providers/migraphx/migraphx_provider_factory.cc +++ b/onnxruntime/core/providers/migraphx/migraphx_provider_factory.cc @@ -39,7 +39,7 @@ struct ProviderInfo_MIGraphX_Impl final : ProviderInfo_MIGraphX { } std::unique_ptr CreateMIGraphXPinnedAllocator(int16_t device_id, const char* name) override { - return std::make_unique(device_id, name); + return std::make_unique(device_id, name); } } g_info; diff --git a/onnxruntime/core/providers/nnapi/nnapi_builtin/nnapi_execution_provider.cc b/onnxruntime/core/providers/nnapi/nnapi_builtin/nnapi_execution_provider.cc index 27bd584e2d3c6..28cfde817a620 100644 --- a/onnxruntime/core/providers/nnapi/nnapi_builtin/nnapi_execution_provider.cc +++ b/onnxruntime/core/providers/nnapi/nnapi_builtin/nnapi_execution_provider.cc @@ -81,6 +81,7 @@ NnapiExecutionProvider::~NnapiExecutionProvider() {} std::vector> NnapiExecutionProvider::GetCapability(const onnxruntime::GraphViewer& graph_viewer, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const { std::vector> result; const logging::Logger& logger = *GetLogger(); diff --git a/onnxruntime/core/providers/nnapi/nnapi_builtin/nnapi_execution_provider.h b/onnxruntime/core/providers/nnapi/nnapi_builtin/nnapi_execution_provider.h index ebf9372eb668d..a2269fdd89436 100644 --- a/onnxruntime/core/providers/nnapi/nnapi_builtin/nnapi_execution_provider.h +++ b/onnxruntime/core/providers/nnapi/nnapi_builtin/nnapi_execution_provider.h @@ -26,6 +26,7 @@ class NnapiExecutionProvider : public IExecutionProvider { std::vector> GetCapability(const onnxruntime::GraphViewer& graph_view, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const override; #if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) diff --git a/onnxruntime/core/providers/openvino/backends/basic_backend.cc b/onnxruntime/core/providers/openvino/backends/basic_backend.cc index b02a6c2f3c734..e406b1b02259d 100644 --- a/onnxruntime/core/providers/openvino/backends/basic_backend.cc +++ b/onnxruntime/core/providers/openvino/backends/basic_backend.cc @@ -683,7 +683,7 @@ void BasicBackend::CompleteAsyncInference(Ort::KernelContext& context, OVInferRe const auto& out_name = item.first; auto node = item.second; Ort::UnownedValue output_tensor = GetOutputTensor(context, - std::move(out_name), + out_name, subgraph_context_.output_names, node); auto mem_info = output_tensor.GetTensorMemoryInfo(); diff --git a/onnxruntime/core/providers/openvino/openvino_execution_provider.cc b/onnxruntime/core/providers/openvino/openvino_execution_provider.cc index 8d3ff0270c1bb..5d481edfe056e 100644 --- a/onnxruntime/core/providers/openvino/openvino_execution_provider.cc +++ b/onnxruntime/core/providers/openvino/openvino_execution_provider.cc @@ -121,6 +121,7 @@ OpenVINOExecutionProvider::~OpenVINOExecutionProvider() { std::vector> OpenVINOExecutionProvider::GetCapability(const GraphViewer& graph_viewer, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const { std::vector> result; diff --git a/onnxruntime/core/providers/openvino/openvino_execution_provider.h b/onnxruntime/core/providers/openvino/openvino_execution_provider.h index bbcca583b074b..020aec16e507c 100644 --- a/onnxruntime/core/providers/openvino/openvino_execution_provider.h +++ b/onnxruntime/core/providers/openvino/openvino_execution_provider.h @@ -51,6 +51,7 @@ class OpenVINOExecutionProvider : public IExecutionProvider { std::vector> GetCapability(const GraphViewer& graph_viewer, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const override; Status Compile(const std::vector& fused_nodes, diff --git a/onnxruntime/core/providers/openvino/openvino_provider_factory.cc b/onnxruntime/core/providers/openvino/openvino_provider_factory.cc index 9ba19f34cf764..be99378381794 100644 --- a/onnxruntime/core/providers/openvino/openvino_provider_factory.cc +++ b/onnxruntime/core/providers/openvino/openvino_provider_factory.cc @@ -17,7 +17,6 @@ namespace onnxruntime { namespace openvino_ep { - void ParseConfigOptions(ProviderInfo& pi) { if (pi.config_options == nullptr) return; diff --git a/onnxruntime/core/providers/qnn/builder/onnx_ctx_model_helper.cc b/onnxruntime/core/providers/qnn/builder/onnx_ctx_model_helper.cc index 3df231e53e7c0..26642459a6863 100644 --- a/onnxruntime/core/providers/qnn/builder/onnx_ctx_model_helper.cc +++ b/onnxruntime/core/providers/qnn/builder/onnx_ctx_model_helper.cc @@ -10,6 +10,7 @@ #include "core/providers/qnn/ort_api.h" #include "core/providers/qnn/builder/qnn_utils.h" #include "core/providers/qnn/builder/qnn_model.h" +#include "core/providers/qnn/shared_context.h" namespace onnxruntime { namespace qnn { @@ -76,6 +77,7 @@ Status CreateNodeArgs(const std::vector& names, const OnnxTensorInfo& tensor_info = tensor_info_table.at(name); std::unique_ptr tensor_type = Factory::Create(); tensor_type->mutable_tensor_type()->set_elem_type(tensor_info.data_type_); + tensor_type->mutable_tensor_type()->mutable_shape(); for (size_t j = 0; j < tensor_info.shape_.size(); ++j) { tensor_type->mutable_tensor_type()->mutable_shape()->add_dim()->set_dim_value(tensor_info.shape_[j]); } @@ -198,38 +200,18 @@ Status LoadQnnCtxFromOnnxGraph(const onnxruntime::GraphViewer& graph_viewer, return Status::OK(); } -// Figure out the real context cache file path -// return true if context cache file exists -bool ValidateContextCacheFilePath(bool is_qnn_ctx_model, - const std::string& customer_context_cache_path, - const onnxruntime::PathString& model_pathstring, - onnxruntime::PathString& context_cache_path) { - // always try the path set by user first, it's the only way to set it if load model from memory - if (!customer_context_cache_path.empty()) { - context_cache_path = ToPathString(customer_context_cache_path); - } else if (!model_pathstring.empty()) { // model loaded from file - if (is_qnn_ctx_model) { - // it's a context cache model, just use the model path - context_cache_path = model_pathstring; - } else if (!model_pathstring.empty()) { - // this is not a normal Onnx model, no customer path, create a default path for generation: model_path + _ctx.onnx - context_cache_path = model_pathstring + ToPathString("_ctx.onnx"); - } - } - - return std::filesystem::is_regular_file(context_cache_path) && std::filesystem::exists(context_cache_path); -} - Status CreateEPContextNodes(Model* model, unsigned char* buffer, uint64_t buffer_size, const std::string& sdk_build_version, const std::vector& fused_nodes_and_graphs, const QnnModelLookupTable& qnn_models, - const onnxruntime::PathString& context_cache_path, + const onnxruntime::PathString& context_model_path, bool qnn_context_embed_mode, uint64_t max_spill_fill_buffer_size, - const logging::Logger& logger) { + const logging::Logger& logger, + bool share_ep_contexts, + bool stop_share_ep_contexts) { auto& graph = model->MainGraph(); using namespace ONNX_NAMESPACE; @@ -262,15 +244,50 @@ Status CreateEPContextNodes(Model* model, std::string cache_payload(buffer, buffer + buffer_size); ep_node.AddAttribute(EP_CACHE_CONTEXT, cache_payload); } else { - onnxruntime::PathString context_bin_path = context_cache_path + ToPathString("_" + graph_name + ".bin"); - std::string context_cache_name(std::filesystem::path(context_bin_path).filename().string()); - std::ofstream of_stream(context_bin_path.c_str(), std::ofstream::binary); - if (!of_stream) { - LOGS(logger, ERROR) << "Failed to open create context file."; - return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Failed to open context cache file."); + onnxruntime::PathString context_bin_path; + std::string context_cache_name; + auto pos = context_model_path.find_last_of(ORT_TSTR(".")); + if (pos != std::string::npos) { + context_bin_path = context_model_path.substr(0, pos); + } else { + context_bin_path = context_model_path; + } + std::string graph_name_in_file(graph_name); + auto name_pos = graph_name_in_file.find_first_of(kQnnExecutionProvider); + if (name_pos != std::string::npos) { + graph_name_in_file.replace(name_pos, strlen(kQnnExecutionProvider), ""); } - of_stream.write(reinterpret_cast(buffer), buffer_size); + context_bin_path = context_bin_path + ToPathString(graph_name_in_file + ".bin"); + context_cache_name = std::filesystem::path(context_bin_path).filename().string(); + + // If generate ctx.onnx with share_ep_context enabled, all ctx.onnx should point to the same ctx.bin + if (share_ep_contexts) { + auto shared_ctx_bin_name = SharedContext::GetInstance().GetSharedCtxBinFileName(); + if (shared_ctx_bin_name.empty()) { + SharedContext::GetInstance().SetSharedCtxBinFileName(context_cache_name); + } else { + context_cache_name = shared_ctx_bin_name; + auto model_folder_path = std::filesystem::path(context_bin_path).parent_path().string(); + context_bin_path = ToPathString(model_folder_path + "/" + context_cache_name); + } + } + + // Write the ctx.bin file for the case: 1. no share_ep_context enabled, write for every session + // 2. share_ep_context enabled, only write for the last session which has stop_share_ep_contexts enabled + if (!share_ep_contexts || (share_ep_contexts && stop_share_ep_contexts)) { + std::ofstream of_stream(context_bin_path.c_str(), std::ofstream::binary); + if (!of_stream) { + LOGS(logger, ERROR) << "Failed to open create context file."; + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Failed to open context cache file."); + } + of_stream.write(reinterpret_cast(buffer), buffer_size); + } + ep_node.AddAttribute(EP_CACHE_CONTEXT, context_cache_name); + if (share_ep_contexts && stop_share_ep_contexts) { + SharedContext::GetInstance().ResetSharedCtxBinFileName(); + } + ep_node.AddAttribute(MAX_SIZE, static_cast(max_spill_fill_buffer_size)); } } else { diff --git a/onnxruntime/core/providers/qnn/builder/onnx_ctx_model_helper.h b/onnxruntime/core/providers/qnn/builder/onnx_ctx_model_helper.h index 3dfa0ae21001b..b037d5c3d2336 100644 --- a/onnxruntime/core/providers/qnn/builder/onnx_ctx_model_helper.h +++ b/onnxruntime/core/providers/qnn/builder/onnx_ctx_model_helper.h @@ -38,11 +38,6 @@ Status CreateNodeArgs(const std::vector& names, std::vector& node_args, onnxruntime::Graph& graph); -bool ValidateContextCacheFilePath(bool is_qnn_ctx_model, - const std::string& customer_context_cache_path, - const onnxruntime::PathString& model_pathstring, - onnxruntime::PathString& context_cache_path); - Status GetEpContextFromMainNode(const onnxruntime::Node& main_context_node, const onnxruntime::PathString& ctx_onnx_model_path, QnnBackendManager* qnn_backend_manager, @@ -67,9 +62,11 @@ Status CreateEPContextNodes(Model* model, const std::string& sdk_build_version, const std::vector& fused_nodes_and_graphs, const std::unordered_map>& qnn_models, - const onnxruntime::PathString& context_cache_path, + const onnxruntime::PathString& context_model_path, bool qnn_context_embed_mode, uint64_t max_spill_fill_buffer_size, - const logging::Logger& logger); + const logging::Logger& logger, + bool share_ep_contexts, + bool stop_share_ep_contexts); } // namespace qnn } // namespace onnxruntime diff --git a/onnxruntime/core/providers/qnn/builder/op_builder_factory.cc b/onnxruntime/core/providers/qnn/builder/op_builder_factory.cc index 3d66003fb2bca..77579dfc793ee 100644 --- a/onnxruntime/core/providers/qnn/builder/op_builder_factory.cc +++ b/onnxruntime/core/providers/qnn/builder/op_builder_factory.cc @@ -47,6 +47,7 @@ OpBuilderRegistrations::OpBuilderRegistrations() { CreateSimpleOpBuilder("Sin", *this); CreateSimpleOpBuilder("Sqrt", *this); CreateSimpleOpBuilder("Sub", *this); + CreateSimpleOpBuilder("Sum", *this); CreateSimpleOpBuilder("Tanh", *this); CreateSimpleOpBuilder("Concat", *this); diff --git a/onnxruntime/core/providers/qnn/builder/opbuilder/base_op_builder.h b/onnxruntime/core/providers/qnn/builder/opbuilder/base_op_builder.h index a79f4056083c5..df9d0de8e0e3e 100644 --- a/onnxruntime/core/providers/qnn/builder/opbuilder/base_op_builder.h +++ b/onnxruntime/core/providers/qnn/builder/opbuilder/base_op_builder.h @@ -158,6 +158,7 @@ class BaseOpBuilder : public IOpBuilder { {"Softmax", QNN_OP_SOFTMAX}, {"Sqrt", QNN_OP_ELEMENT_WISE_SQUARE_ROOT}, {"Sub", QNN_OP_ELEMENT_WISE_SUBTRACT}, + {"Sum", QNN_OP_ELEMENT_WISE_ADD}, {"Tanh", QNN_OP_TANH}, {"Transpose", QNN_OP_TRANSPOSE}, {"GridSample", QNN_OP_GRID_SAMPLE}, diff --git a/onnxruntime/core/providers/qnn/builder/opbuilder/simple_op_builder.cc b/onnxruntime/core/providers/qnn/builder/opbuilder/simple_op_builder.cc index 48c637cd2e951..229d86082f6dc 100644 --- a/onnxruntime/core/providers/qnn/builder/opbuilder/simple_op_builder.cc +++ b/onnxruntime/core/providers/qnn/builder/opbuilder/simple_op_builder.cc @@ -56,11 +56,18 @@ Status SimpleOpBuilder::ExplicitOpCheck(QnnModelWrapper& qnn_model_wrapper, padding_mode.c_str()); } - // ONNX's Min and Max operators accept a variable number of inputs (i.e., variadic). - // However, QNN's Min and Max operators must take in exactly two inputs. + // ONNX's Min, Max, and Sum operators accept a variable number of inputs (i.e., variadic). + // However, QNN's Min, Max, and Add operators must take in exactly two inputs. if (op_type == "Min" || op_type == "Max") { ORT_RETURN_IF_NOT(node_unit.Inputs().size() == 2, - "QNN EP only supports Min and Max operators with exactly 2 inputs."); + "QNN EP only supports ", op_type.c_str(), " operator with exactly 2 inputs."); + } + + if (op_type == "Sum") { + size_t inputs_num = node_unit.Inputs().size(); + ORT_RETURN_IF_NOT(inputs_num == 2, + "QNN EP supports Sum operator with QNN_OP_ELEMENT_WISE_ADD, which takes exactly 2 inputs. Got ONNX's Sum operator with ", + std::to_string(inputs_num).c_str(), " inputs."); } if (op_type == "DequantizeLinear") { diff --git a/onnxruntime/core/providers/qnn/builder/opbuilder/softmax_op_builder.cc b/onnxruntime/core/providers/qnn/builder/opbuilder/softmax_op_builder.cc index 7326523737383..e8acaf75143d8 100644 --- a/onnxruntime/core/providers/qnn/builder/opbuilder/softmax_op_builder.cc +++ b/onnxruntime/core/providers/qnn/builder/opbuilder/softmax_op_builder.cc @@ -1,6 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#include +#include +#include +#include +#include + #include "core/providers/qnn/builder/opbuilder/base_op_builder.h" #include "core/providers/qnn/builder/qnn_utils.h" #include "core/providers/qnn/builder/qnn_model_wrapper.h" @@ -14,10 +20,6 @@ class SoftmaxOpBuilder : public BaseOpBuilder { SoftmaxOpBuilder() : BaseOpBuilder("SoftmaxOpBuilder") {} ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(SoftmaxOpBuilder); - Status IsOpSupported(QnnModelWrapper& qnn_model_wrapper, - const NodeUnit& node_unit, - const logging::Logger& logger) const override final ORT_MUST_USE_RESULT; - protected: Status ProcessInputs(QnnModelWrapper& qnn_model_wrapper, const NodeUnit& node_unit, @@ -37,34 +39,24 @@ constexpr int32_t GetDefaultAxisAttribute(int opset_version) { return opset_version < 13 ? 1 : -1; } -Status SoftmaxOpBuilder::IsOpSupported(QnnModelWrapper& qnn_model_wrapper, - const NodeUnit& node_unit, - const logging::Logger& logger) const { - ORT_UNUSED_PARAMETER(logger); - const int opset_version = node_unit.SinceVersion(); +std::vector FlattenShapeFromAxis(std::vector& input_shape, int32_t axis) { + /* + Return the shape with all dimensions multiplied onward from the specified axis. If axis is 0, the returned shape + will include an additional batch of size 1 as the first dimension. + */ + assert(axis >= 0 && axis < input_shape.size()); + std::vector output_shape(input_shape.begin(), input_shape.begin() + axis); - // The QNN HTP backend only supports an `axis` attribute that refers to the last input dimension. - // QNN EP is able to support arbitrary axis attributes by wrapping the QNN operator with transposes. - // However, the exception is Softmax/LogSoftmax with opset < 13. For these older ONNX operators, only - // axis == input_rank - 1 is supported. - if (opset_version < 13) { - const std::string& op_type = node_unit.OpType(); - - int32_t axis = GetDefaultAxisAttribute(opset_version); - Qnn_Scalar_t axis_qnn_scalar = QNN_SCALAR_INIT; - ORT_RETURN_IF_ERROR(ProcessAxisAttribute(qnn_model_wrapper, node_unit, axis_qnn_scalar, axis)); - std::vector input_shape; - ORT_RETURN_IF_NOT(qnn_model_wrapper.GetOnnxShape(node_unit.Inputs()[0].node_arg, input_shape), - "QNN EP: Cannot get shape for Softmax input"); - ORT_RETURN_IF(axis != static_cast(input_shape.size() - 1), - "QNN ", op_type.c_str(), - " only supports an `axis` attribute equal to input_rank-1 (or -1) for ONNX opset < 13"); + if (axis == 0) { + output_shape.push_back(1); // Additional batch included } + output_shape.push_back( + std::accumulate(input_shape.begin() + axis, input_shape.end(), 1, std::multiplies())); - return AddToModelBuilder(qnn_model_wrapper, node_unit, logger, true); + return output_shape; } -static std::vector GetTransposePermToUseLastAxis(uint32_t input_rank, uint32_t axis) { +std::vector GetTransposePermToUseLastAxis(uint32_t input_rank, uint32_t axis) { assert(axis < input_rank); std::vector transpose_perm; transpose_perm.reserve(input_rank); @@ -87,58 +79,84 @@ Status SoftmaxOpBuilder::ProcessInputs(QnnModelWrapper& qnn_model_wrapper, bool do_op_validation) const { const bool is_npu_backend = IsNpuBackend(qnn_model_wrapper.GetQnnBackendType()); const auto& inputs = node_unit.Inputs(); + const std::string& input_name = inputs[0].node_arg.Name(); assert(inputs.size() == 1); - int32_t axis = GetDefaultAxisAttribute(node_unit.SinceVersion()); + const int opset_version = node_unit.SinceVersion(); + int32_t axis = GetDefaultAxisAttribute(opset_version); Qnn_Scalar_t axis_qnn_scalar = QNN_SCALAR_INIT; ORT_RETURN_IF_ERROR(ProcessAxisAttribute(qnn_model_wrapper, node_unit, axis_qnn_scalar, axis)); TensorInfo input_info = {}; ORT_RETURN_IF_ERROR(qnn_model_wrapper.GetTensorInfo(inputs[0], input_info)); - const size_t input_rank = input_info.shape.size(); - - // If the axis attribute refers to the last dimension, then process the input as normal. - if (!is_npu_backend || axis == static_cast(input_rank) - 1) { - return ProcessInput(qnn_model_wrapper, inputs[0], logger, input_names); - } - - // - // The axis does **not** refer to the last input dimension. Must wrap transposes around the operator to be able to use - // QNN's Softmax operator, which always uses an axis value that refers to the last dimension. - // - - std::vector transpose_perm = GetTransposePermToUseLastAxis(static_cast(input_rank), - static_cast(axis)); - - const std::string& input_name = inputs[0].node_arg.Name(); - std::string op_input_name = input_info.is_initializer ? input_name : input_name + "_ort_qnn_ep_transpose"; - input_names.push_back(op_input_name); - - std::vector op_input_shape = input_info.shape; - op_input_shape[input_rank - 1] = input_info.shape[axis]; - op_input_shape[axis] = input_info.shape[input_rank - 1]; - + size_t input_rank = input_info.shape.size(); ORT_RETURN_IF(input_info.is_initializer, "QNN EP does not support (Log)Softmax with an initializer input, ", "which should be optimized away by the ORT optimizer"); - // Input is dynamic, so add transpose node before input. - const bool is_graph_input = qnn_model_wrapper.IsGraphInput(input_name); - - ORT_RETURN_IF_ERROR(qnn_model_wrapper.AddTransposeNode(node_unit.Index(), - input_name, - op_input_name, + if (opset_version < 13) { + /* + For Onnx Softmax with opset < 13, its behavior is to flatten the input starting from the axis, and perform + softmax operation along the axis dimension, then reshape back to the original input shape. + QNN EP is able to support arbitrary axis attribute by wrapping reshapes around the operator. + + Here provides an example: + Given an input with shape=(3, 4, 5) and axis=1. Its behavior is to reshape the input to (3, 20), perform softmax, + and then reshape back to (3, 4, 5). + + When axis equals 0, the reshape output shape includes an additional batch of size 1 as the first dimension. + Here provides an example: + Given an input with shape=(3, 4, 5) and axis=0. Its behavior is to reshape the input to (1, 60), perform softmax, + and then reshape back to (3, 4, 5). + */ + std::string reshape_output_name = input_name + "_ort_qnn_ep_reshape"; + std::vector reshape_output_shape = FlattenShapeFromAxis(input_info.shape, axis); + + // Input is dynamic, so add reshape node before input. + const bool is_graph_input = qnn_model_wrapper.IsGraphInput(input_name); + + ORT_RETURN_IF_ERROR(qnn_model_wrapper.AddReshapeNode(input_name, + reshape_output_name, input_info.shape, - transpose_perm, - op_input_shape, + reshape_output_shape, input_info.qnn_data_type, input_info.quant_param, do_op_validation, - is_graph_input)); - - Qnn_TensorType_t tensor_type = qnn_model_wrapper.GetTensorType(op_input_name); - QnnTensorWrapper input_tensorwrapper(op_input_name, tensor_type, input_info.qnn_data_type, - std::move(input_info.quant_param), std::move(op_input_shape), {}); - ORT_RETURN_IF_NOT(qnn_model_wrapper.AddTensorWrapper(std::move(input_tensorwrapper)), "Failed to add tensor."); + is_graph_input, + false)); + input_names.push_back(reshape_output_name); + } else if (is_npu_backend && axis != static_cast(input_rank) - 1) { + /* + For Onnx Softmax with opset >= 13, the QNN HTP backend only supports the axis attribute that refers to the last + input dimension. + QNN EP is able to support arbitrary axis attribute by wrapping transposes around the operator. + */ + std::string transpose_output_name = input_name + "_ort_qnn_ep_transpose"; + std::vector transpose_perm = GetTransposePermToUseLastAxis(static_cast(input_rank), + static_cast(axis)); + + std::vector transpose_output_shape = input_info.shape; + transpose_output_shape[input_rank - 1] = input_info.shape[axis]; + transpose_output_shape[axis] = input_info.shape[input_rank - 1]; + + // Input is dynamic, so add transpose node before input. + const bool is_graph_input = qnn_model_wrapper.IsGraphInput(input_name); + + ORT_RETURN_IF_ERROR(qnn_model_wrapper.AddTransposeNode(node_unit.Index(), + input_name, + transpose_output_name, + input_info.shape, + transpose_perm, + transpose_output_shape, + input_info.qnn_data_type, + input_info.quant_param, + do_op_validation, + is_graph_input, + false)); + input_names.push_back(transpose_output_name); + } else { + // Process the input as normal. + return ProcessInput(qnn_model_wrapper, inputs[0], logger, input_names); + } return Status::OK(); } @@ -151,76 +169,105 @@ Status SoftmaxOpBuilder::ProcessAttributesAndOutputs(QnnModelWrapper& qnn_model_ const bool is_npu_backend = IsNpuBackend(qnn_model_wrapper.GetQnnBackendType()); const std::string& op_type = node_unit.OpType(); const auto& outputs = node_unit.Outputs(); + const std::string& orig_output_name = outputs[0].node_arg.Name(); assert(outputs.size() == 1); - int32_t axis = GetDefaultAxisAttribute(node_unit.SinceVersion()); + const int opset_version = node_unit.SinceVersion(); + int32_t axis = GetDefaultAxisAttribute(opset_version); Qnn_Scalar_t axis_qnn_scalar = QNN_SCALAR_INIT; ORT_RETURN_IF_ERROR(ProcessAxisAttribute(qnn_model_wrapper, node_unit, axis_qnn_scalar, axis)); TensorInfo output_info = {}; ORT_RETURN_IF_ERROR(qnn_model_wrapper.GetTensorInfo(outputs[0], output_info)); - const size_t output_rank = output_info.shape.size(); - const bool axis_is_last_dim = static_cast(axis) == output_rank - 1; + size_t output_rank = output_info.shape.size(); - // If axis refers to the last dimension, process outputs as usual. - if (!is_npu_backend || axis_is_last_dim) { - QnnParamWrapper axis_param(node_unit.Index(), node_unit.Name(), QNN_OP_SOFTMAX_PARAM_AXIS, axis_qnn_scalar); + if (opset_version < 13) { + std::string reshape_input_name = orig_output_name + "_ort_qnn_ep_reshape"; + + std::vector reshape_input_shape = FlattenShapeFromAxis(output_info.shape, axis); + if (axis == 0) { + // Override axis due to the inserted batch=1 to the first dimension + axis_qnn_scalar.uint32Value = 1; + } + QnnParamWrapper axis_param(node_unit.Index(), node_unit.Name(), QNN_OP_SOFTMAX_PARAM_AXIS, axis_qnn_scalar); std::vector param_tensor_names; param_tensor_names.push_back(axis_param.GetParamTensorName()); qnn_model_wrapper.AddParamWrapper(std::move(axis_param)); - return ProcessOutputs(qnn_model_wrapper, node_unit, - std::move(input_names), - std::move(param_tensor_names), - logger, do_op_validation, GetQnnOpType(op_type)); - } - - // - // The axis **does** not refer to the last dimension. Must wrap the operator with Transposes to be able to use - // QNN's Softmax operator, which only supports an axis that refers to the last dimension. - // - - axis_qnn_scalar.uint32Value = static_cast(output_rank - 1); // NOTE: override axis. - QnnParamWrapper axis_param(node_unit.Index(), node_unit.Name(), QNN_OP_SOFTMAX_PARAM_AXIS, axis_qnn_scalar); - - std::vector param_tensor_names; - param_tensor_names.push_back(axis_param.GetParamTensorName()); - qnn_model_wrapper.AddParamWrapper(std::move(axis_param)); - - const std::string& orig_output_name = outputs[0].node_arg.Name(); - std::string op_output_name = orig_output_name + "_ort_qnn_ep_transpose"; - - std::vector op_output_shape = output_info.shape; - op_output_shape[output_rank - 1] = output_info.shape[axis]; - op_output_shape[axis] = output_info.shape[output_rank - 1]; - - QnnTensorWrapper output_tensorwrapper(op_output_name, QNN_TENSOR_TYPE_NATIVE, output_info.qnn_data_type, - output_info.quant_param.Copy(), std::vector(op_output_shape)); - ORT_RETURN_IF_NOT(qnn_model_wrapper.AddTensorWrapper(std::move(output_tensorwrapper)), "Failed to add tensor."); - ORT_RETURN_IF_NOT(qnn_model_wrapper.CreateQnnNode(utils::GetNodeName(node_unit), - QNN_OP_PACKAGE_NAME_QTI_AISW, - GetQnnOpType(node_unit.OpType()), - std::move(input_names), - {op_output_name}, - std::move(param_tensor_names)), - "Failed to add node."); - - const bool is_graph_output = qnn_model_wrapper.IsGraphOutput(orig_output_name); - std::vector transpose_perm = GetTransposePermToUseLastAxis(static_cast(output_rank), - static_cast(axis)); - - ORT_RETURN_IF_ERROR(qnn_model_wrapper.AddTransposeNode(node_unit.Index(), - op_output_name, + QnnTensorWrapper output_tensorwrapper(reshape_input_name, QNN_TENSOR_TYPE_NATIVE, output_info.qnn_data_type, + output_info.quant_param.Copy(), std::vector(reshape_input_shape)); + ORT_RETURN_IF_NOT(qnn_model_wrapper.AddTensorWrapper(std::move(output_tensorwrapper)), "Failed to add tensor."); + ORT_RETURN_IF_NOT(qnn_model_wrapper.CreateQnnNode(utils::GetNodeName(node_unit), + QNN_OP_PACKAGE_NAME_QTI_AISW, + GetQnnOpType(node_unit.OpType()), + std::move(input_names), + {reshape_input_name}, + std::move(param_tensor_names)), + "Failed to add node."); + + const bool is_graph_output = qnn_model_wrapper.IsGraphOutput(orig_output_name); + ORT_RETURN_IF_ERROR(qnn_model_wrapper.AddReshapeNode(reshape_input_name, orig_output_name, - op_output_shape, - transpose_perm, + reshape_input_shape, output_info.shape, output_info.qnn_data_type, output_info.quant_param, do_op_validation, false, is_graph_output)); + } else if (is_npu_backend && axis != static_cast(output_rank) - 1) { + std::string transpose_input_name = orig_output_name + "_ort_qnn_ep_transpose"; + + std::vector transpose_input_shape = output_info.shape; + transpose_input_shape[output_rank - 1] = output_info.shape[axis]; + transpose_input_shape[axis] = output_info.shape[output_rank - 1]; + + // Override axis due to the actual shape after the inserted transpose node + axis_qnn_scalar.uint32Value = static_cast(output_rank) - 1; + + QnnParamWrapper axis_param(node_unit.Index(), node_unit.Name(), QNN_OP_SOFTMAX_PARAM_AXIS, axis_qnn_scalar); + std::vector param_tensor_names; + param_tensor_names.push_back(axis_param.GetParamTensorName()); + qnn_model_wrapper.AddParamWrapper(std::move(axis_param)); + + QnnTensorWrapper output_tensorwrapper(transpose_input_name, QNN_TENSOR_TYPE_NATIVE, output_info.qnn_data_type, + output_info.quant_param.Copy(), std::vector(transpose_input_shape)); + ORT_RETURN_IF_NOT(qnn_model_wrapper.AddTensorWrapper(std::move(output_tensorwrapper)), "Failed to add tensor."); + ORT_RETURN_IF_NOT(qnn_model_wrapper.CreateQnnNode(utils::GetNodeName(node_unit), + QNN_OP_PACKAGE_NAME_QTI_AISW, + GetQnnOpType(node_unit.OpType()), + std::move(input_names), + {transpose_input_name}, + std::move(param_tensor_names)), + "Failed to add node."); + + const bool is_graph_output = qnn_model_wrapper.IsGraphOutput(orig_output_name); + std::vector transpose_perm = GetTransposePermToUseLastAxis(static_cast(output_rank), + static_cast(axis)); + + ORT_RETURN_IF_ERROR(qnn_model_wrapper.AddTransposeNode(node_unit.Index(), + transpose_input_name, + orig_output_name, + transpose_input_shape, + transpose_perm, + output_info.shape, + output_info.qnn_data_type, + output_info.quant_param, + do_op_validation, + false, + is_graph_output)); + } else { + QnnParamWrapper axis_param(node_unit.Index(), node_unit.Name(), QNN_OP_SOFTMAX_PARAM_AXIS, axis_qnn_scalar); + std::vector param_tensor_names; + param_tensor_names.push_back(axis_param.GetParamTensorName()); + qnn_model_wrapper.AddParamWrapper(std::move(axis_param)); + + return ProcessOutputs(qnn_model_wrapper, node_unit, + std::move(input_names), + std::move(param_tensor_names), + logger, do_op_validation, GetQnnOpType(op_type)); + } return Status::OK(); } diff --git a/onnxruntime/core/providers/qnn/builder/qnn_backend_manager.cc b/onnxruntime/core/providers/qnn/builder/qnn_backend_manager.cc index bcde69beceef7..6b9f6a5e73e0f 100644 --- a/onnxruntime/core/providers/qnn/builder/qnn_backend_manager.cc +++ b/onnxruntime/core/providers/qnn/builder/qnn_backend_manager.cc @@ -52,6 +52,70 @@ static const char* DlError() { #endif } +Status ReadBinaryFromFile(const std::string& file_path, uint8_t* buffer, size_t buffer_size) { + ORT_RETURN_IF(nullptr == buffer, "Binary buffer is nullptr"); + std::ifstream in(file_path, std::ifstream::binary); + ORT_RETURN_IF(!in, "Failed to open input file: ", file_path.c_str()); + ORT_RETURN_IF(!in.read(reinterpret_cast(buffer), buffer_size), "Failed to read the contents of: ", file_path.c_str()); + return Status::OK(); +} + +Status QnnBackendManager::ParseLoraConfig(std::string lora_config_path) { + LOGS_DEFAULT(INFO) << "Acquiring the QnnInterface " << lora_config_path; + + // QNN Lora Config file format should be a single line, with the graph name first, + // followed by the qnn lora context binary path, separated by a semicolon (;) + // Example: ; + LOGS_DEFAULT(INFO) << "Loading Lora Config " << lora_config_path; + std::ifstream file(lora_config_path); + std::string line; + + if (file.is_open()) { + if (std::getline(file, line)) { + std::istringstream ss(line); + std::string graph_name; + std::string lora_adapter_bin_path; + + if (std::getline(ss, graph_name, ';') && std::getline(ss, lora_adapter_bin_path)) { + size_t buffer_size = std::filesystem::file_size(lora_adapter_bin_path.c_str()); + + ORT_RETURN_IF(0 == buffer_size, "Received path to an empty file. Nothing to deserialize."); + std::unique_ptr buffer = std::make_unique(buffer_size); + void* voidBufferPtr = static_cast(buffer.get()); + QnnContext_Buffer_t contextBuffer{QNN_CONTEXT_BUFFER_VERSION_1, + {QNN_CONTEXTMEMTYPE_RAW, {{voidBufferPtr, buffer_size}}}}; + + auto status = ReadBinaryFromFile(lora_adapter_bin_path, + reinterpret_cast(buffer.get()), + buffer_size); + + ORT_RETURN_IF(status != Status::OK(), "Failed to read binary data."); + Qnn_GraphHandle_t graph; + bool graph_retrieve_success = false; + for (size_t cIdx = 0; cIdx < contexts_.size(); cIdx++) { + auto graph_retrieve_rt = qnn_interface_.graphRetrieve(contexts_[cIdx], graph_name.c_str(), &graph); + if (QNN_SUCCESS != graph_retrieve_rt) { + continue; + } + + graph_retrieve_success = true; + + auto context_apply_binary_section_rt = qnn_interface_.contextApplyBinarySection( + contexts_[cIdx], graph, QNN_CONTEXT_SECTION_UPDATABLE, &contextBuffer, profile_backend_handle_, nullptr); + ORT_RETURN_IF(QNN_SUCCESS != context_apply_binary_section_rt, "Failed to apply binary section."); + break; + } + ORT_RETURN_IF_NOT(graph_retrieve_success, "Failed to retrieve graph: ", graph_name, " and apply binary section."); + } + } + file.close(); + } else { + LOGS_DEFAULT(ERROR) << "Unable to load Lora Config " << lora_config_path; + } + + return Status::OK(); +} + template Status QnnBackendManager::GetQnnInterfaceProvider(const char* lib_path, const char* interface_provider_name, @@ -470,8 +534,10 @@ Status QnnBackendManager::InitializeProfiling() { QnnProfile_Level_t qnn_profile_level = QNN_PROFILE_LEVEL_BASIC; if (ProfilingLevel::BASIC == profiling_level_merge_) { qnn_profile_level = QNN_PROFILE_LEVEL_BASIC; + LOGS_DEFAULT(VERBOSE) << "Profiling level set to basic."; } else if (ProfilingLevel::DETAILED == profiling_level_merge_) { qnn_profile_level = QNN_PROFILE_LEVEL_DETAILED; + LOGS_DEFAULT(VERBOSE) << "Profiling level set to detailed."; } Qnn_ErrorHandle_t result = qnn_interface_.profileCreate(backend_handle_, qnn_profile_level, &profile_backend_handle_); ORT_RETURN_IF(QNN_PROFILE_NO_ERROR != result, "Failed to create QNN profile! Error: ", QnnErrorHandleToString(result)); @@ -536,7 +602,7 @@ Status SetQnnContextConfig(ContextPriority context_priority, QnnContext_Config_t return Status::OK(); } -Status QnnBackendManager::CreateContext() { +Status QnnBackendManager::CreateContext(bool enable_htp_weight_sharing) { if (true == context_created_) { LOGS_DEFAULT(INFO) << "Context created already."; return Status::OK(); @@ -545,7 +611,7 @@ Status QnnBackendManager::CreateContext() { QnnContext_Config_t context_config_weight_sharing = QNN_CONTEXT_CONFIG_INIT; QnnHtpContext_CustomConfig_t custom_config; custom_config.option = QNN_HTP_CONTEXT_CONFIG_OPTION_WEIGHT_SHARING_ENABLED; - custom_config.weightSharingEnabled = enable_htp_weight_sharing_; + custom_config.weightSharingEnabled = enable_htp_weight_sharing; context_config_weight_sharing.option = QNN_CONTEXT_CONFIG_OPTION_CUSTOM; context_config_weight_sharing.customConfig = &custom_config; @@ -808,7 +874,8 @@ Status QnnBackendManager::LoadCachedQnnContextFromBuffer(char* buffer, uint64_t // or generate Qnn context binary is enabled -- to get the max spill fill buffer size Status QnnBackendManager::SetupBackend(const logging::Logger& logger, bool load_from_cached_context, - bool need_load_system_lib) { + bool need_load_system_lib, + bool share_ep_contexts) { std::lock_guard lock(logger_recursive_mutex_); if (backend_setup_completed_) { LOGS(logger, VERBOSE) << "Backend setup already!"; @@ -863,9 +930,18 @@ Status QnnBackendManager::SetupBackend(const logging::Logger& logger, LOGS(logger, VERBOSE) << "InitializeProfiling succeed."; } + bool enable_htp_weight_sharing = false; + if (share_ep_contexts && !load_from_cached_context) { +#if defined(__aarch64__) || defined(_M_ARM64) + LOGS(logger, WARNING) << "Weight sharing only available with offline generation on x64 platform, not work on real device."; +#else + enable_htp_weight_sharing = true; +#endif + } + if (!load_from_cached_context) { if (status.IsOK()) { - status = CreateContext(); + status = CreateContext(enable_htp_weight_sharing); } if (status.IsOK()) { LOGS(logger, VERBOSE) << "CreateContext succeed."; diff --git a/onnxruntime/core/providers/qnn/builder/qnn_backend_manager.h b/onnxruntime/core/providers/qnn/builder/qnn_backend_manager.h index 3592af41f03df..137b3856d431d 100644 --- a/onnxruntime/core/providers/qnn/builder/qnn_backend_manager.h +++ b/onnxruntime/core/providers/qnn/builder/qnn_backend_manager.h @@ -43,7 +43,6 @@ struct QnnBackendManagerConfig { uint32_t device_id; QnnHtpDevice_Arch_t htp_arch; uint32_t soc_model; - bool enable_htp_weight_sharing; }; class QnnBackendManager : public std::enable_shared_from_this { @@ -67,8 +66,7 @@ class QnnBackendManager : public std::enable_shared_from_this qnn_saver_path_(config.qnn_saver_path), device_id_(config.device_id), htp_arch_(config.htp_arch), - soc_model_(config.soc_model), - enable_htp_weight_sharing_(config.enable_htp_weight_sharing) { + soc_model_(config.soc_model) { } ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(QnnBackendManager); @@ -84,7 +82,8 @@ class QnnBackendManager : public std::enable_shared_from_this // Initializes handles to QNN resources (device, logger, etc.). // NOTE: This function locks the internal `logger_recursive_mutex_`. - Status SetupBackend(const logging::Logger& logger, bool load_from_cached_context, bool need_load_system_lib); + Status SetupBackend(const logging::Logger& logger, bool load_from_cached_context, + bool need_load_system_lib, bool share_ep_contexts); Status CreateHtpPowerCfgId(uint32_t deviceId, uint32_t coreId, uint32_t& htp_power_config_id); @@ -140,6 +139,8 @@ class QnnBackendManager : public std::enable_shared_from_this const Qnn_Tensor_t& qnn_tensor, Qnn_MemHandle_t& mem_handle); + Status ParseLoraConfig(std::string lora_config); + private: Status LoadBackend(); @@ -155,7 +156,7 @@ class QnnBackendManager : public std::enable_shared_from_this Status ReleaseProfilehandle(); - Status CreateContext(); + Status CreateContext(bool enable_htp_weight_sharing); Status ReleaseContext(); @@ -298,7 +299,6 @@ class QnnBackendManager : public std::enable_shared_from_this uint32_t device_id_ = 0; QnnHtpDevice_Arch_t htp_arch_ = QNN_HTP_DEVICE_ARCH_NONE; uint32_t soc_model_ = QNN_SOC_MODEL_UNKNOWN; - bool enable_htp_weight_sharing_ = false; }; } // namespace qnn diff --git a/onnxruntime/core/providers/qnn/qnn_execution_provider.cc b/onnxruntime/core/providers/qnn/qnn_execution_provider.cc index 3fc537066ae0b..142a7362ad6ae 100644 --- a/onnxruntime/core/providers/qnn/qnn_execution_provider.cc +++ b/onnxruntime/core/providers/qnn/qnn_execution_provider.cc @@ -4,6 +4,8 @@ #include "qnn_execution_provider.h" #include +#include +#include #include #include "core/providers/qnn/ort_api.h" @@ -22,6 +24,60 @@ namespace onnxruntime { constexpr const char* QNN = "QNN"; +static std::string MakeSharedLibraryPath(std::string_view name) { +#if defined(_WIN32) + return MakeString(name, ".dll"); +#else + return MakeString("lib", name, ".so"); +#endif +} + +const std::string kDefaultCpuBackendPath = MakeSharedLibraryPath("QnnCpu"); +const std::string kDefaultGpuBackendPath = MakeSharedLibraryPath("QnnGpu"); +const std::string kDefaultHtpBackendPath = MakeSharedLibraryPath("QnnHtp"); +const std::string kDefaultSaverBackendPath = MakeSharedLibraryPath("QnnSaver"); + +static bool ParseBackendTypeName(std::string_view backend_type_name, std::string& backend_path) { + constexpr std::string_view kCpuBackendTypeName{"cpu"}; + constexpr std::string_view kGpuBackendTypeName{"gpu"}; + constexpr std::string_view kHtpBackendTypeName{"htp"}; + constexpr std::string_view kSaverBackendTypeName{"saver"}; + + constexpr std::array kAllowedBackendTypeNames{ + kCpuBackendTypeName, + kGpuBackendTypeName, + kHtpBackendTypeName, + kSaverBackendTypeName, + }; + + std::optional associated_backend_path{}; + if (backend_type_name == kCpuBackendTypeName) { + associated_backend_path = kDefaultCpuBackendPath; + } else if (backend_type_name == kGpuBackendTypeName) { + associated_backend_path = kDefaultGpuBackendPath; + } else if (backend_type_name == kHtpBackendTypeName) { + associated_backend_path = kDefaultHtpBackendPath; + } else if (backend_type_name == kSaverBackendTypeName) { + associated_backend_path = kDefaultSaverBackendPath; + } + + if (associated_backend_path.has_value()) { + backend_path = std::move(*associated_backend_path); + return true; + } + + std::ostringstream warning{}; + warning << "Invalid backend type name: " << backend_type_name << ". Allowed backend type names: "; + for (size_t i = 0; i < kAllowedBackendTypeNames.size(); ++i) { + warning << kAllowedBackendTypeNames[i]; + if (i + 1 < kAllowedBackendTypeNames.size()) { + warning << ", "; + } + } + LOGS_DEFAULT(WARNING) << warning.str(); + return false; +} + static void ParseProfilingLevel(std::string profiling_level_string, qnn::ProfilingLevel& profiling_level) { std::transform(profiling_level_string.begin(), @@ -195,17 +251,45 @@ QNNExecutionProvider::QNNExecutionProvider(const ProviderOptions& provider_optio share_ep_contexts_ = config_options->GetConfigOrDefault(kOrtSessionOptionShareEpContexts, "0") == "1"; LOGS_DEFAULT(VERBOSE) << "User specified option - share EP contexts across sessions: " << share_ep_contexts_; + + stop_share_ep_contexts_ = + config_options->GetConfigOrDefault(kOrtSessionOptionStopShareEpContexts, "0") == "1"; + LOGS_DEFAULT(VERBOSE) << "User specified option - stop share EP contexts across sessions: " << stop_share_ep_contexts_; } - static const std::string BACKEND_PATH = "backend_path"; - auto backend_path_pos = provider_options_map.find(BACKEND_PATH); + std::string backend_path{}; + { + std::optional backend_path_from_options{}; - std::string backend_path; - if (backend_path_pos != provider_options_map.end()) { - backend_path = backend_path_pos->second; - LOGS_DEFAULT(VERBOSE) << "Backend path: " << backend_path; - } else { - LOGS_DEFAULT(ERROR) << "No backend path provided."; + static const std::string BACKEND_TYPE = "backend_type"; + static const std::string BACKEND_PATH = "backend_path"; + + auto backend_type_it = provider_options_map.find(BACKEND_TYPE); + auto backend_path_it = provider_options_map.find(BACKEND_PATH); + + if (backend_type_it != provider_options_map.end() && backend_path_it != provider_options_map.end()) { + ORT_THROW("Only one of '", BACKEND_TYPE, "' and '", BACKEND_PATH, "' should be set."); + } + + if (backend_type_it != provider_options_map.end()) { + if (std::string parsed_backend_path; ParseBackendTypeName(backend_type_it->second, parsed_backend_path)) { + backend_path_from_options = parsed_backend_path; + } else { + LOGS_DEFAULT(ERROR) << "Failed to parse '" << BACKEND_TYPE << "' value."; + } + } else if (backend_path_it != provider_options_map.end()) { + backend_path_from_options = backend_path_it->second; + } + + if (backend_path_from_options.has_value()) { + backend_path = std::move(*backend_path_from_options); + } else { + const auto& default_backend_path = kDefaultHtpBackendPath; + backend_path = default_backend_path; + LOGS_DEFAULT(WARNING) << "Unable to determine backend path from provider options. Using default."; + } + + LOGS_DEFAULT(VERBOSE) << "Using backend path: " << backend_path; } std::string profiling_file_path; @@ -333,19 +417,8 @@ QNNExecutionProvider::QNNExecutionProvider(const ProviderOptions& provider_optio LOGS_DEFAULT(VERBOSE) << "User specified enable_htp_fp16_precision: " << enable_HTP_FP16_precision_; } - bool enable_htp_weight_sharing = false; - static const std::string QNN_HTP_WEIGHT_SHARING_ENABLED = "enable_htp_weight_sharing"; - auto htp_weight_sharing_enabled_pos = provider_options_map.find(QNN_HTP_WEIGHT_SHARING_ENABLED); - if (htp_weight_sharing_enabled_pos != provider_options_map.end()) { - if ("1" == htp_weight_sharing_enabled_pos->second) { - enable_htp_weight_sharing = true; - } else if ("0" == htp_weight_sharing_enabled_pos->second) { - enable_htp_weight_sharing = false; - } else { - LOGS_DEFAULT(VERBOSE) << "Invalid enable_htp_weight_sharing: " << enable_htp_weight_sharing - << " only 0 or 1 allowed. Set to 0."; - } - LOGS_DEFAULT(VERBOSE) << "User specified enable_htp_weight_sharing: " << enable_htp_weight_sharing; + if (qnn_context_embed_mode_ && share_ep_contexts_) { + LOGS_DEFAULT(ERROR) << "[EP context generation:] Weight sharing enabled conflict with EP context embed mode. Inference will not work as expected!"; } // Add this option because this feature requires QnnSystem lib and it's no supported for Windows x86_64 platform @@ -384,17 +457,26 @@ QNNExecutionProvider::QNNExecutionProvider(const ProviderOptions& provider_optio } } - qnn_backend_manager_ = qnn::QnnBackendManager::Create( - qnn::QnnBackendManagerConfig{backend_path, - profiling_level_etw, - profiling_level, - profiling_file_path, - context_priority, - qnn_saver_path, - device_id_, - htp_arch, - soc_model, - enable_htp_weight_sharing}); + // For context binary generation with weight sharing enabled, use the QnnBackendManager from the shared context if it exits + // So that all graphs from later sessions will be compiled into the same QNN context + if (context_cache_enabled_ && share_ep_contexts_ && SharedContext::GetInstance().GetSharedQnnBackendManager()) { + qnn_backend_manager_ = SharedContext::GetInstance().GetSharedQnnBackendManager(); + // Clear the QnnBackendManager from singleton to stop the resource share + if (stop_share_ep_contexts_) { + SharedContext::GetInstance().ResetSharedQnnBackendManager(); + } + } else { + qnn_backend_manager_ = qnn::QnnBackendManager::Create( + qnn::QnnBackendManagerConfig{backend_path, + profiling_level_etw, + profiling_level, + profiling_file_path, + context_priority, + qnn_saver_path, + device_id_, + htp_arch, + soc_model}); + } #if defined(_WIN32) if (onnxruntime::logging::EtwRegistrationManager::SupportsETW()) { @@ -655,6 +737,7 @@ static void PartitionCtxModel(const onnxruntime::GraphViewer& graph_viewer, std::vector> QNNExecutionProvider::GetCapability(const onnxruntime::GraphViewer& graph_viewer, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const { std::vector> result; @@ -686,7 +769,9 @@ QNNExecutionProvider::GetCapability(const onnxruntime::GraphViewer& graph_viewer // It will load the QnnSystem lib if is_qnn_ctx_model=true, and // delay the Qnn context creation to Compile() using the cached context binary // or generate context cache enable, need to use use QnnSystem lib to parse the binary to get the max spill fill buffer size - auto rt = qnn_backend_manager_->SetupBackend(logger, is_qnn_ctx_model, context_cache_enabled_ && enable_spill_fill_buffer_); + auto rt = qnn_backend_manager_->SetupBackend(logger, is_qnn_ctx_model, + context_cache_enabled_ && enable_spill_fill_buffer_, + share_ep_contexts_); if (Status::OK() != rt) { LOGS(logger, ERROR) << "QNN SetupBackend failed " << rt.ErrorMessage(); return result; @@ -904,25 +989,33 @@ Status QNNExecutionProvider::CompileFromOrtGraph(const std::vector& fused_nodes_and_graphs, std::vector& node_compute_funcs) { const auto& logger = *GetLogger(); bool is_qnn_ctx_model = qnn::IsFusedGraphHasCtxNode(fused_nodes_and_graphs); - onnxruntime::PathString context_cache_path; + onnxruntime::PathString context_model_path; bool is_ctx_file_exist = false; if (is_qnn_ctx_model || context_cache_enabled_) { const onnxruntime::GraphViewer& graph_viewer_0(fused_nodes_and_graphs[0].filtered_graph); - is_ctx_file_exist = qnn::ValidateContextCacheFilePath(is_qnn_ctx_model, - context_cache_path_cfg_, - graph_viewer_0.ModelPath().native(), - context_cache_path); + // Figure out the EP context model path from model path or session option + GetContextOnnxModelFilePath(context_cache_path_cfg_, + graph_viewer_0.ModelPath().native(), + context_model_path); } - ORT_RETURN_IF(is_ctx_file_exist && !is_qnn_ctx_model && context_cache_enabled_, - "The inference session is created from normal ONNX model. And an EP context model file is provided and existed. ", - "Please remove the EP context model manually if you want to re-generate it."); - if (is_qnn_ctx_model) { // Get QnnModel from EP shared contexts if (share_ep_contexts_ && SharedContext::GetInstance().HasSharedQnnModels()) { @@ -965,7 +1058,7 @@ Status QNNExecutionProvider::Compile(const std::vector& fused const onnxruntime::GraphViewer& main_ctx_graph_viewer(fused_nodes_and_graphs[main_context_pos].filtered_graph); // Create QNN context from the cached binary, deserialize the QNN graph from the binary ORT_RETURN_IF_ERROR(qnn::LoadQnnCtxFromOnnxGraph(main_ctx_graph_viewer, - context_cache_path, + context_model_path, qnn_backend_manager_.get(), qnn_models, logger, @@ -1025,10 +1118,18 @@ Status QNNExecutionProvider::Compile(const std::vector& fused qnn_backend_manager_->GetSdkVersion(), fused_nodes_and_graphs, qnn_models_, - context_cache_path, + context_model_path, qnn_context_embed_mode_, max_spill_fill_buffer_size, - logger)); + logger, + share_ep_contexts_, + stop_share_ep_contexts_)); + + if (share_ep_contexts_ && !stop_share_ep_contexts_ && + nullptr == SharedContext::GetInstance().GetSharedQnnBackendManager()) { + ORT_RETURN_IF_NOT(SharedContext::GetInstance().SetSharedQnnBackendManager(qnn_backend_manager_), + "Failed to set shared QnnBackendManager."); + } } return Status::OK(); } @@ -1173,6 +1274,12 @@ Status QNNExecutionProvider::OnRunStart(const onnxruntime::RunOptions& run_optio } } + std::string lora_config = ""; + if (TryGetConfigEntry(config_options, kOrtRunOptionsConfigQnnLoraConfig, lora_config)) { + LOGS_DEFAULT(VERBOSE) << "lora_config: " << lora_config; + ORT_RETURN_IF_ERROR(qnn_backend_manager_->ParseLoraConfig(lora_config)); + } + return Status::OK(); } diff --git a/onnxruntime/core/providers/qnn/qnn_execution_provider.h b/onnxruntime/core/providers/qnn/qnn_execution_provider.h index 31c34855ca4c0..d7a5d04d22692 100644 --- a/onnxruntime/core/providers/qnn/qnn_execution_provider.h +++ b/onnxruntime/core/providers/qnn/qnn_execution_provider.h @@ -31,6 +31,7 @@ class QNNExecutionProvider : public IExecutionProvider { std::vector> GetCapability(const onnxruntime::GraphViewer& graph_view, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const override; Status Compile(const std::vector& fused_nodes_and_graphs, @@ -90,6 +91,7 @@ class QNNExecutionProvider : public IExecutionProvider { uint32_t default_rpc_control_latency_ = 0; bool enable_HTP_FP16_precision_ = true; bool share_ep_contexts_ = false; + bool stop_share_ep_contexts_ = false; bool enable_spill_fill_buffer_ = false; #if defined(_WIN32) onnxruntime::logging::EtwRegistrationManager::EtwInternalCallback callback_ETWSink_provider_ = nullptr; diff --git a/onnxruntime/core/providers/qnn/shared_context.h b/onnxruntime/core/providers/qnn/shared_context.h index 81de357dbe677..1402dc30fd37a 100644 --- a/onnxruntime/core/providers/qnn/shared_context.h +++ b/onnxruntime/core/providers/qnn/shared_context.h @@ -61,13 +61,57 @@ class SharedContext { return graph_exist; } + bool SetSharedQnnBackendManager(std::shared_ptr& qnn_backend_manager) { + const std::lock_guard lock(mtx_); + + if (qnn_backend_manager_ != nullptr) { + if (qnn_backend_manager_ == qnn_backend_manager) { + return true; + } + return false; + } + qnn_backend_manager_ = qnn_backend_manager; + return true; + } + + std::shared_ptr GetSharedQnnBackendManager() { + const std::lock_guard lock(mtx_); + return qnn_backend_manager_; + } + + void ResetSharedQnnBackendManager() { + const std::lock_guard lock(mtx_); + qnn_backend_manager_.reset(); + } + + void SetSharedCtxBinFileName(std::string& shared_ctx_bin_file_name) { + const std::lock_guard lock(mtx_); + shared_ctx_bin_file_name_ = shared_ctx_bin_file_name; + } + + const std::string& GetSharedCtxBinFileName() { + const std::lock_guard lock(mtx_); + return shared_ctx_bin_file_name_; + } + + void ResetSharedCtxBinFileName() { + const std::lock_guard lock(mtx_); + shared_ctx_bin_file_name_.clear(); + } + private: SharedContext() = default; ~SharedContext() = default; ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(SharedContext); + // Used for passing through QNN models (deserialized from context binary) across sessions std::vector> shared_qnn_models_; + // Used for compiling multiple models into same QNN context binary + std::shared_ptr qnn_backend_manager_; + // Track the shared ctx binary .bin file name, all _ctx.onnx point to this .bin file + // only the last session generate the .bin file since it contains all graphs from all sessions. + std::string shared_ctx_bin_file_name_; // Producer sessions can be in parallel // Consumer sessions have to be after producer sessions initialized std::mutex mtx_; diff --git a/onnxruntime/core/providers/rknpu/rknpu_execution_provider.cc b/onnxruntime/core/providers/rknpu/rknpu_execution_provider.cc index 10fd81786f977..e9343e2b2e06a 100644 --- a/onnxruntime/core/providers/rknpu/rknpu_execution_provider.cc +++ b/onnxruntime/core/providers/rknpu/rknpu_execution_provider.cc @@ -51,6 +51,7 @@ std::vector> RknpuExecutionProvider::GetSupportedNodes( std::vector> RknpuExecutionProvider::GetCapability(const onnxruntime::GraphViewer& graph_viewer, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const { // Find inputs, initializers and outputs for each supported subgraph std::vector> result; diff --git a/onnxruntime/core/providers/rknpu/rknpu_execution_provider.h b/onnxruntime/core/providers/rknpu/rknpu_execution_provider.h index ce16d63e111d9..75cae37d117a0 100644 --- a/onnxruntime/core/providers/rknpu/rknpu_execution_provider.h +++ b/onnxruntime/core/providers/rknpu/rknpu_execution_provider.h @@ -20,6 +20,7 @@ class RknpuExecutionProvider : public IExecutionProvider { std::vector> GetCapability(const onnxruntime::GraphViewer& graph, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const override; common::Status Compile(const std::vector& fused_nodes_and_graphs, std::vector& node_compute_funcs) override; diff --git a/onnxruntime/core/providers/rocm/rocm_execution_provider.cc b/onnxruntime/core/providers/rocm/rocm_execution_provider.cc index 9d6e9df907ce3..49771488efc44 100644 --- a/onnxruntime/core/providers/rocm/rocm_execution_provider.cc +++ b/onnxruntime/core/providers/rocm/rocm_execution_provider.cc @@ -2441,6 +2441,7 @@ std::unique_ptr ROCMExecutionProvider::GetDataTransf std::vector> ROCMExecutionProvider::GetCapability(const onnxruntime::GraphViewer& graph, const IKernelLookup& kernel_lookup, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const { InlinedVector candidates; // A subset of the above vector. A subset of the tentative_nodes might be moved to CPU. diff --git a/onnxruntime/core/providers/rocm/rocm_execution_provider.h b/onnxruntime/core/providers/rocm/rocm_execution_provider.h index ff2bff7c98723..2baaf2ff1a886 100644 --- a/onnxruntime/core/providers/rocm/rocm_execution_provider.h +++ b/onnxruntime/core/providers/rocm/rocm_execution_provider.h @@ -62,6 +62,7 @@ class ROCMExecutionProvider : public IExecutionProvider { std::vector> GetCapability( const onnxruntime::GraphViewer& graph, const IKernelLookup& kernel_lookup, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const override; int GetDeviceId() const override { return info_.device_id; } diff --git a/onnxruntime/core/providers/shared/utils/utils.cc b/onnxruntime/core/providers/shared/utils/utils.cc index 5b2f2c1fa1b2e..4281b5e53c5fd 100644 --- a/onnxruntime/core/providers/shared/utils/utils.cc +++ b/onnxruntime/core/providers/shared/utils/utils.cc @@ -100,17 +100,6 @@ bool GetClipMinMax(const GraphViewer& graph_viewer, const Node& node, float& min node, min, max, logger); } -// deprecated version that is not able to check if the initializer is constant -bool GetClipMinMax(const InitializedTensorSet& initializers, const Node& node, float& min, float& max, - const logging::Logger& logger) { - return GetClipMinMaxImpl( - [&initializers](const std::string& name) -> const ONNX_NAMESPACE::TensorProto* { - auto entry = initializers.find(name); - return entry == initializers.end() ? nullptr : entry->second; - }, - node, min, max, logger); -} - NodeAttrHelper::NodeAttrHelper(const onnxruntime::Node& node) : node_attributes_(node.GetAttributes()) {} diff --git a/onnxruntime/core/providers/shared/utils/utils.h b/onnxruntime/core/providers/shared/utils/utils.h index ddbae42534711..78da6c76047bd 100644 --- a/onnxruntime/core/providers/shared/utils/utils.h +++ b/onnxruntime/core/providers/shared/utils/utils.h @@ -27,12 +27,6 @@ class NodeUnit; bool GetClipMinMax(const GraphViewer& graph_viewer, const Node& node, float& min, float& max, const logging::Logger& logger); -/// GraphViewer GetConstantInitializer/IsConstantInitializer should be used to ensure the initializer is -/// constant. Low risk for Clip min/max but in general the infrastructure to check if an operator is supported needs -/// to be updated to not use InitializedTensorSet which may contain non-constant initializers. -bool GetClipMinMax(const InitializedTensorSet& initializers, const Node& node, - float& min, float& max, const logging::Logger& logger); - // Get the type of the given NodeArg // Will return false if the given NodeArg has no type bool GetType(const NodeArg& node_arg, int32_t& type, const logging::Logger& logger); diff --git a/onnxruntime/core/providers/shared_library/provider_api.h b/onnxruntime/core/providers/shared_library/provider_api.h index 6ff2572e5e668..9d61e1f12f5b6 100644 --- a/onnxruntime/core/providers/shared_library/provider_api.h +++ b/onnxruntime/core/providers/shared_library/provider_api.h @@ -200,6 +200,7 @@ struct SparseTensor; class TensorSeq; class SessionState; class ModelMetadefIdGenerator; +class GraphOptimizerRegistry; class If; class Loop; diff --git a/onnxruntime/core/providers/shared_library/provider_bridge_provider.cc b/onnxruntime/core/providers/shared_library/provider_bridge_provider.cc index 2dab9f6a402a0..0d01215efaa14 100644 --- a/onnxruntime/core/providers/shared_library/provider_bridge_provider.cc +++ b/onnxruntime/core/providers/shared_library/provider_bridge_provider.cc @@ -332,8 +332,9 @@ bool IAllocator::CalcMemSizeForArrayWithAlignment(size_t nmemb, size_t size, siz std::vector> IExecutionProvider::GetCapability(const onnxruntime::GraphViewer& graph_viewer, const IKernelLookup& kernel_lookup, + const GraphOptimizerRegistry& graph_optimizer_registry, IResourceAccountant* resource_accountant) const { - return g_host->IExecutionProvider__GetCapability(this, graph_viewer, kernel_lookup, resource_accountant); + return g_host->IExecutionProvider__GetCapability(this, graph_viewer, kernel_lookup, graph_optimizer_registry, resource_accountant); } common::Status IExecutionProvider::Compile(const std::vector& fused_nodes_and_graphs, std::vector& node_compute_funcs) { @@ -774,7 +775,7 @@ std::unique_ptr CreateModel(const GraphViewer& graph_viewer, const loggin } // namespace cann #endif -void MurmurHash3::x86_128(const void* key, int len, uint32_t seed, void* out) { +void MurmurHash3::x86_128(const void* key, size_t len, uint32_t seed, void* out) { return g_host->MurmurHash3__x86_128(key, len, seed, out); } diff --git a/onnxruntime/core/providers/shared_library/provider_interfaces.h b/onnxruntime/core/providers/shared_library/provider_interfaces.h index a77f0cb4c27b0..bc8905c225822 100644 --- a/onnxruntime/core/providers/shared_library/provider_interfaces.h +++ b/onnxruntime/core/providers/shared_library/provider_interfaces.h @@ -105,6 +105,8 @@ using ModelMetaData = std::unordered_map; using IOnnxRuntimeOpSchemaCollectionPtr = std::shared_ptr; using IOnnxRuntimeOpSchemaRegistryList = std::list; using InitializedTensorSet = std::unordered_map; +using KeyValueConfig = std::unordered_map; +using SelectionFunc = std::function>(const GraphViewer&, const KeyValueConfig&, const GraphOptimizerRegistry&)>; struct Node__NodeIterator { virtual ~Node__NodeIterator() {} @@ -151,6 +153,10 @@ struct ConstGraphNodes_Iterator { struct ProviderHost { virtual const OrtApiBase* OrtGetApiBase() = 0; + virtual Status GetOptimizerByName(const std::string& name, + const GraphOptimizerRegistry& graph_optimizer_registry, + SelectionFunc& selection_func) = 0; + virtual void* HeapAllocate(size_t size) = 0; virtual void HeapFree(void*) = 0; @@ -253,6 +259,7 @@ struct ProviderHost { // IExecutionProvider virtual std::vector> IExecutionProvider__GetCapability(const IExecutionProvider* p, const onnxruntime::GraphViewer& graph_viewer, const IExecutionProvider::IKernelLookup& kernel_lookup, + const GraphOptimizerRegistry& graph_optimizer_registry, IResourceAccountant* resource_accountant) = 0; virtual common::Status IExecutionProvider__Compile(IExecutionProvider* p, const std::vector& fused_nodes_and_graphs, std::vector& node_compute_funcs) = 0; @@ -604,6 +611,8 @@ struct ProviderHost { virtual int FunctionProto__metadata_props_size(const ONNX_NAMESPACE::FunctionProto* p) = 0; virtual ONNX_NAMESPACE::StringStringEntryProto* FunctionProto__add_metadata_props(ONNX_NAMESPACE::FunctionProto* p) = 0; + virtual void InferShapes(const std::string& m, const std::string& save_path) = 0; + virtual void InferShapes(ONNX_NAMESPACE::ModelProto& m) = 0; virtual void RegisterSchema(const std::string& domain, const OrtCustomOp* op) = 0; virtual void DeregisterSchema(const std::string& domain, const std::string& op_type, int version) = 0; virtual const ONNX_NAMESPACE::OpSchema* GetSchema(const std::string& name, const int maxInclusiveVersion, const std::string& domain) = 0; @@ -627,6 +636,8 @@ struct ProviderHost { virtual std::unique_ptr ComputeCapability__construct(std::unique_ptr t_sub_graph) = 0; virtual void ComputeCapability__operator_delete(ComputeCapability* p) = 0; virtual std::unique_ptr& ComputeCapability__SubGraph(ComputeCapability* p) = 0; + virtual void ComputeCapability__copy_optimization_func(ComputeCapability* p, ComputeCapability* selection_cc) = 0; + virtual void ComputeCapability__add_nodes_to_optimize(ComputeCapability* p, std::unique_ptr optimization_cc) = 0; // DataTransferManager virtual Status DataTransferManager__CopyTensor(const DataTransferManager* p, const Tensor& src, Tensor& dst) = 0; @@ -1001,6 +1012,7 @@ struct ProviderHost { virtual const Graph* Graph__ParentGraph(const Graph* p) const = 0; virtual Graph* Graph__MutableParentGraph(Graph* p) = 0; virtual const std::string& Graph__Name(const Graph* p) const noexcept = 0; + virtual void Graph__SetName(Graph* p, const std::string& name) const noexcept = 0; virtual const std::filesystem::path& Graph__ModelPath(const Graph* p) const = 0; virtual const std::vector& Graph__GetInputsIncludingInitializers(const Graph* p) const noexcept = 0; virtual bool Graph__IsSubgraph(const Graph* p) = 0; @@ -1279,7 +1291,7 @@ struct ProviderHost { virtual std::unique_ptr cann__CreateModel(const GraphViewer& graph_viewer, const logging::Logger& logger) = 0; #endif - virtual void MurmurHash3__x86_128(const void* key, int len, uint32_t seed, void* out) = 0; + virtual void MurmurHash3__x86_128(const void* key, size_t len, uint32_t seed, void* out) = 0; #ifdef _WIN32 virtual std::string ToUTF8String(const std::wstring& s) = 0; diff --git a/onnxruntime/core/providers/shared_library/provider_wrappedtypes.h b/onnxruntime/core/providers/shared_library/provider_wrappedtypes.h index a502ce9c66f69..5f0f9ca4c8584 100644 --- a/onnxruntime/core/providers/shared_library/provider_wrappedtypes.h +++ b/onnxruntime/core/providers/shared_library/provider_wrappedtypes.h @@ -527,6 +527,9 @@ struct ComputeCapability final { std::unique_ptr& SubGraph() { return g_host->ComputeCapability__SubGraph(this); } + void copy_optimization_func(ComputeCapability* selection_cc) { g_host->ComputeCapability__copy_optimization_func(this, selection_cc); } + void add_nodes_to_optimize(std::unique_ptr optimization_cc) { g_host->ComputeCapability__add_nodes_to_optimize(this, std::move(optimization_cc)); } + ComputeCapability() = delete; ComputeCapability(const ComputeCapability&) = delete; void operator=(const ComputeCapability&) = delete; @@ -1047,6 +1050,7 @@ struct Graph final { const Graph* ParentGraph() const { return g_host->Graph__ParentGraph(this); } Graph* MutableParentGraph() { return g_host->Graph__MutableParentGraph(this); } const std::string& Name() const noexcept { return g_host->Graph__Name(this); } + void SetName(const std::string& name) noexcept { return g_host->Graph__SetName(this, name); } const std::filesystem::path& ModelPath() const { return g_host->Graph__ModelPath(this); } const std::vector& GetInputsIncludingInitializers() const noexcept { return g_host->Graph__GetInputsIncludingInitializers(this); } bool IsSubgraph() const { return g_host->Graph__IsSubgraph(this); } diff --git a/onnxruntime/core/providers/snpe/snpe_execution_provider.cc b/onnxruntime/core/providers/snpe/snpe_execution_provider.cc index c7fc6d3a556a7..4eae7c97f9ab0 100644 --- a/onnxruntime/core/providers/snpe/snpe_execution_provider.cc +++ b/onnxruntime/core/providers/snpe/snpe_execution_provider.cc @@ -72,6 +72,7 @@ SNPEExecutionProvider::~SNPEExecutionProvider() {} std::vector> SNPEExecutionProvider::GetCapability(const onnxruntime::GraphViewer& graph, const IKernelLookup& kernel_lookup, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const { std::vector candidates; for (auto& node_index : graph.GetNodesInTopologicalOrder()) { diff --git a/onnxruntime/core/providers/snpe/snpe_execution_provider.h b/onnxruntime/core/providers/snpe/snpe_execution_provider.h index 99033649fcbbf..4b7987b38ee93 100644 --- a/onnxruntime/core/providers/snpe/snpe_execution_provider.h +++ b/onnxruntime/core/providers/snpe/snpe_execution_provider.h @@ -19,6 +19,7 @@ class SNPEExecutionProvider : public IExecutionProvider { std::vector> GetCapability( const onnxruntime::GraphViewer& graph, const IKernelLookup& kernel_lookup, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const override; std::shared_ptr GetKernelRegistry() const override; diff --git a/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider.cc b/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider.cc index e59d252793532..ded135bf50ec8 100644 --- a/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider.cc +++ b/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider.cc @@ -1282,6 +1282,22 @@ TensorrtExecutionProvider::PerThreadContext& TensorrtExecutionProvider::GetPerTh return *context; } +std::vector ParseTrtPreviewFeatures(const std::string& str) { + std::vector featureNames{SplitToStringVec(str, ',')}; + + std::vector previewFeatures; + previewFeatures.reserve(featureNames.size()); + for (auto featureName : featureNames) { + if (featureName == "ALIASED_PLUGIN_IO_10_03") { + previewFeatures.push_back(nvinfer1::PreviewFeature::kALIASED_PLUGIN_IO_10_03); + } else { + throw std::invalid_argument(std::string("Unkown or unsupported preview feature: ") + featureName); + } + } + + return previewFeatures; +} + TensorrtExecutionProvider::TensorrtExecutionProvider(const TensorrtExecutionProviderInfo& info) : IExecutionProvider{onnxruntime::kTensorrtExecutionProvider, OrtDevice(OrtDevice::GPU, OrtDevice::MemType::DEFAULT, @@ -1380,6 +1396,7 @@ TensorrtExecutionProvider::TensorrtExecutionProvider(const TensorrtExecutionProv cuda_graph_enable_ = info.cuda_graph_enable; engine_hw_compatible_ = info.engine_hw_compatible; op_types_to_exclude_ = info.op_types_to_exclude; + preview_features_ = ParseTrtPreviewFeatures(info.preview_features); } else { try { const std::string max_partition_iterations_env = onnxruntime::GetEnvironmentVar(tensorrt_env_vars::kMaxPartitionIterations); @@ -2279,8 +2296,9 @@ SubGraphCollection_t TensorrtExecutionProvider::GetSupportedList(SubGraphCollect auto network_flags = 0; #if NV_TENSORRT_MAJOR > 8 network_flags |= fp16_enable_ || int8_enable_ ? 0 : 1U << static_cast(nvinfer1::NetworkDefinitionCreationFlag::kSTRONGLY_TYPED); -#endif +#else network_flags |= 1U << static_cast(nvinfer1::NetworkDefinitionCreationFlag::kEXPLICIT_BATCH); +#endif auto trt_network = std::unique_ptr(trt_builder->createNetworkV2(network_flags)); auto trt_parser = tensorrt_ptr::unique_pointer(nvonnxparser::createParser(*trt_network, trt_logger)); @@ -2459,6 +2477,7 @@ bool TensorrtExecutionProvider::DetectTensorRTGraphCycles(SubGraphCollection_t& std::vector> TensorrtExecutionProvider::GetCapability(const GraphViewer& graph, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& graph_optimizer_registry, IResourceAccountant* /* resource_accountant */) const { // Construct subgraph capability from node list std::vector> result; @@ -2664,11 +2683,61 @@ TensorrtExecutionProvider::GetCapability(const GraphViewer& graph, } } + /** + * Enable EP related L2+ graph optimizations: + * + * 1. Calls provider bridge API to lookup pre-defined optimizer by name and get selection function. + * - Example: g_host->GetOptimizerByName(optimizer_name, graph_optimizer_registry, selection_func) + * 2. Executes the selection function to obtain the selection ComputeCapability. + * - ComputeCapability.optimize_func would be set by the optimizer to the function that does the optimization. + * 3. Uses the selection ComputeCapability to create the optimization ComputeCapability. + * 4. Returns the final ComputeCapability, with nodes_to_optimize set to the optimization ComputeCapability. + * + * Current available optimizations: + * - (ConstantFoldingDQ) constant folding on DQ nodes, i.e. dequantize INT32, UINT16, INT16 constant to FP32. + */ + + SelectionFunc selection_func; + std::vector> selection_cc; + + // Prepare for ConstantFoldingDQ optimizer + // Note: The NodeIndex here is the node index in the graph, not the index in node vector in supported_nodes_vector. + std::unordered_set trt_selection_node_set; // The qualified dq nodes selected by TRT EP + std::unordered_map consumer_to_dq; // consumer node -> dq node + + if (dla_enable_) { + std::string optimizer_name = "ConstantFoldingDQ"; + const std::unordered_map key_value_config; + auto status = g_host->GetOptimizerByName(optimizer_name, graph_optimizer_registry, selection_func); + if (status == Status::OK()) { + if (selection_func) { + selection_cc = selection_func(graph, key_value_config, graph_optimizer_registry); + SelectQualifiedDQNode(graph, trt_selection_node_set, consumer_to_dq); + } + } else { + LOGS_DEFAULT(WARNING) << "[TensorRT EP] Can't get optimizer " << optimizer_name; + } + } + + // Create ComputeCapability int number_of_trt_nodes = 0, subgraph_index = 0; - for (const auto& group : supported_nodes_vector) { + for (auto& group : supported_nodes_vector) { if (!group.first.empty()) { + if (!selection_cc.empty()) { + // Include DQ nodes that are filtered out by TRT parser + UpdateSupportedNodeVectorForDQ(graph, group, supported_nodes_vector, consumer_to_dq); + } + std::unique_ptr sub_graph = GetSubGraph(group, graph, model_hash, subgraph_index); - result.push_back(ComputeCapability::Create(std::move(sub_graph))); + auto compute_capability = ComputeCapability::Create(std::move(sub_graph)); + + // add optimization ComputeCapability to node_to_optimize + for (auto& cc : selection_cc) { + std::unique_ptr optimization_cc = CreateOptimizationComputeCapability(cc.get(), trt_selection_node_set, compute_capability.get()); + compute_capability->add_nodes_to_optimize(std::move(optimization_cc)); + } + + result.push_back(std::move(compute_capability)); number_of_trt_nodes += static_cast(group.first.size()); subgraph_index++; } @@ -2839,8 +2908,9 @@ Status TensorrtExecutionProvider::CreateNodeComputeInfoFromGraph(const GraphView auto network_flags = 0; #if NV_TENSORRT_MAJOR > 8 network_flags |= fp16_enable_ || int8_enable_ ? 0 : 1U << static_cast(nvinfer1::NetworkDefinitionCreationFlag::kSTRONGLY_TYPED); -#endif +#else network_flags |= 1U << static_cast(nvinfer1::NetworkDefinitionCreationFlag::kEXPLICIT_BATCH); +#endif auto trt_network = std::unique_ptr(trt_builder->createNetworkV2(network_flags)); auto trt_config = std::unique_ptr(trt_builder->createBuilderConfig()); auto trt_parser = tensorrt_ptr::unique_pointer(nvonnxparser::createParser(*trt_network, trt_logger)); @@ -3135,6 +3205,11 @@ Status TensorrtExecutionProvider::CreateNodeComputeInfoFromGraph(const GraphView LOGS_DEFAULT(VERBOSE) << "[TensorRT EP] Tactic sources are limited using " << tactic_sources_; } + // Set preview feature flags + for (auto feature : preview_features_) { + trt_config->setPreviewFeature(feature, true); + } + // Build TRT engine (if needed) and load TRT engine if: // (1) Graph has no dynamic shape input // (2) All the dynamic shape inputs have associated explicit profiles specified by user @@ -3475,7 +3550,8 @@ Status TensorrtExecutionProvider::CreateNodeComputeInfoFromGraph(const GraphView context_memory_sharing_enable_, &max_ctx_mem_size_, dynamic_range_map, engine_decryption_enable_, engine_decryption_, engine_encryption_, timing_cache_enable_, global_cache_path_, force_timing_cache_match_, detailed_build_log_, build_heuristics_enable_, sparsity_enable_, builder_optimization_level_, - auxiliary_streams_, !tactic_sources_.empty(), tactics, cuda_graph_enable_, cache_prefix_, cache_suffix, engine_hw_compatible_}; + auxiliary_streams_, !tactic_sources_.empty(), tactics, cuda_graph_enable_, cache_prefix_, cache_suffix, engine_hw_compatible_, + preview_features_}; *state = p.release(); return 0; }; @@ -3757,6 +3833,11 @@ Status TensorrtExecutionProvider::CreateNodeComputeInfoFromGraph(const GraphView } #endif + // Set preview feature flags + for (auto feature : trt_state->preview_features) { + trt_config->setPreviewFeature(feature, true); + } + // Build engine std::unique_ptr serialized_engine; { diff --git a/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider.h b/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider.h index 873826a81c51b..f6c8f7d7dd46b 100644 --- a/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider.h +++ b/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider.h @@ -201,6 +201,7 @@ struct TensorrtFuncState { std::string cache_prefix; std::string cache_suffix; bool engine_hw_compatible = false; + std::vector preview_features; }; // Minimum information to construct kernel function state for direct engine load code path @@ -249,6 +250,7 @@ class TensorrtExecutionProvider : public IExecutionProvider { std::vector> GetCapability(const GraphViewer& graph, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& graph_optimizer_registry, IResourceAccountant* /* resource_accountant */) const override; int GetDeviceId() const { return device_id_; } @@ -332,6 +334,7 @@ class TensorrtExecutionProvider : public IExecutionProvider { std::string cache_prefix_; bool engine_hw_compatible_ = false; std::string op_types_to_exclude_; + std::vector preview_features_; // The format is as for TENSORRT_VERSION: (MAJOR * 100 + MINOR) * 100 + PATCH int32_t trt_version_; @@ -592,5 +595,35 @@ class TensorrtExecutionProvider : public IExecutionProvider { * This function only creates the instance at the first time it's being called." */ nvinfer1::IBuilder* GetBuilder(TensorrtLogger& trt_logger) const; + + /** + * This is the helper function for ConstantFoldingDQ graph transformer. + * + * It selects the qualified/required DQ node to be optimized as well as provides a mapping table + * to help TRT EP later include the DQ node which is filtered out by TRT parser. + */ + void SelectQualifiedDQNode(const GraphViewer& graph, + std::unordered_set& selection_node_set, + std::unordered_map& consumer_to_dq) const; + + /** + * This function returns an optimization ComputeCapability that is limited to: + * 1. the DQ nodes in this individual TRT ComputeCapability + * 2. the DQ nodes that are qualified and selected by TRT EP + * + * It also needs to make sure the DQ nodes is a subset of the complete list of DQ nodes to optimize in original selection ComputeCapability. + * Finally, copy the optimization function from the original selection ComputeCapability. + */ + std::unique_ptr CreateOptimizationComputeCapability(ComputeCapability* selection_cc, + std::unordered_set& trt_selection_node_set, + ComputeCapability* trt_cc) const; + /** + * This function helps add back the DQ nodes that are filtered out by TRT parser. + * The reason is the DQ nodes can be optimized and dequantized by applying ConstantFoldingDQ optimizer by ORT L2+ optimization. + */ + void UpdateSupportedNodeVectorForDQ(const GraphViewer& graph, + SubGraph_t& supported_node_vector, + SubGraphCollection_t& supported_nodes_vector, + std::unordered_map consumer_to_dq) const; }; } // namespace onnxruntime diff --git a/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider_custom_ops.cc b/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider_custom_ops.cc index e93d3565fe33d..90a4294fb47f0 100644 --- a/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider_custom_ops.cc +++ b/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider_custom_ops.cc @@ -60,19 +60,31 @@ common::Status CreateTensorRTCustomOpDomainList(std::vector& TensorrtLogger trt_logger = GetTensorrtLogger(false); initLibNvInferPlugins(&trt_logger, ""); -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 4996) // Ignore warning C4996: 'nvinfer1::*' was declared deprecated -#endif - int num_plugin_creator = 0; - auto plugin_creators = getPluginRegistry()->getPluginCreatorList(&num_plugin_creator); + auto plugin_creators = getPluginRegistry()->getAllCreators(&num_plugin_creator); std::unordered_set registered_plugin_names; for (int i = 0; i < num_plugin_creator; i++) { auto plugin_creator = plugin_creators[i]; - std::string plugin_name(plugin_creator->getPluginName()); - LOGS_DEFAULT(VERBOSE) << "[TensorRT EP] " << plugin_name << ", version : " << plugin_creator->getPluginVersion(); + nvinfer1::AsciiChar const* plugin_name = nullptr; + if (std::strcmp(plugin_creators[i]->getInterfaceInfo().kind, "PLUGIN CREATOR_V1") == 0) { +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4996) // Ignore warning C4996: 'nvinfer1::*' was declared deprecated +#endif + auto plugin_creator_v1 = static_cast(plugin_creator); + plugin_name = plugin_creator_v1->getPluginName(); + LOGS_DEFAULT(VERBOSE) << "[TensorRT EP] " << plugin_name << ", version : " << plugin_creator_v1->getPluginVersion(); +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + } else if (std::strcmp(plugin_creators[i]->getInterfaceInfo().kind, "PLUGIN CREATOR_V3ONE") == 0) { + auto plugin_creator_v3 = static_cast(plugin_creator); + plugin_name = plugin_creator_v3->getPluginName(); + LOGS_DEFAULT(VERBOSE) << "[TensorRT EP][V3ONE] " << plugin_name << ", version : " << plugin_creator_v3->getPluginVersion(); + } else { + ORT_THROW("Unknown plugin creator type"); + } // plugin has different versions and we only register once if (registered_plugin_names.find(plugin_name) != registered_plugin_names.end()) { @@ -80,15 +92,11 @@ common::Status CreateTensorRTCustomOpDomainList(std::vector& } created_custom_op_list.push_back(std::make_unique(onnxruntime::kTensorrtExecutionProvider, nullptr)); // Make sure TensorRTCustomOp object won't be cleaned up - created_custom_op_list.back().get()->SetName(plugin_creator->getPluginName()); + created_custom_op_list.back().get()->SetName(plugin_name); custom_op_domain->custom_ops_.push_back(created_custom_op_list.back().get()); registered_plugin_names.insert(plugin_name); } -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - custom_op_domain->domain_ = "trt.plugins"; domain_list.push_back(custom_op_domain.get()); } catch (const std::exception&) { diff --git a/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider_helper.cc b/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider_helper.cc index 92fa101118506..b99cb4f52ed59 100644 --- a/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider_helper.cc +++ b/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider_helper.cc @@ -15,7 +15,7 @@ std::string GetUniqueGraphName(const Graph& graph) { uint32_t hash[4] = {0, 0, 0, 0}; auto hash_str = [&hash](const std::string& str) { - MurmurHash3::x86_128(str.data(), gsl::narrow_cast(str.size()), hash[0], &hash); + MurmurHash3::x86_128(str.data(), str.size(), hash[0], &hash); }; // Hash all nodes' name @@ -258,4 +258,133 @@ void TensorrtExecutionProvider::SetAllGraphInputs(Graph& graph) const { graph.SetInputs(graph_inputs_including_initializers); } + +/** + * This is the helper function for ConstantFoldingDQ graph transformer. + * + * It selects the qualified/required DQ node to be optimized as well as provides a mapping table + * to help TRT EP later include the DQ node which is filtered out by TRT parser. + */ +void TensorrtExecutionProvider::SelectQualifiedDQNode(const GraphViewer& graph, + std::unordered_set& selection_node_set, + std::unordered_map& consumer_to_dq) const { + LOGS_DEFAULT(VERBOSE) << "[TensorRT EP] Select qualified DQ nodes ..."; + const std::vector& node_index = graph.GetNodesInTopologicalOrder(1 /*priority-based topological sort*/); + for (auto index : node_index) { + auto* node = graph.GetNode(index); + if (!node) { + continue; + } + + const auto* input_def = node->InputDefs()[0]; // Get NodeArg of the initializer of the DequantizeLinear node; + auto data_type = input_def->TypeAsProto()->tensor_type().elem_type(); + auto constant_initializer = graph.IsConstantInitializer(input_def->Name(), true); + + // Node selection: (i.e. initializer -> DQ -> bias of X) + // 1. DequantizeLinear op + // 2. DQ node does not produce graph output, single consumer + // 3. The first input of DQ is constant initializer. + // 4. The data type of initializer is INT32, UINT16 or INT16 + // 5. X should be Gemm, Conv or LayerNormalization ? + if (node->OpType() == "DequantizeLinear" && + node->GetOutputEdgesCount() == 1 && + (data_type == ONNX_NAMESPACE::TensorProto_DataType_INT32 || data_type == ONNX_NAMESPACE::TensorProto_DataType_INT16 || data_type == ONNX_NAMESPACE::TensorProto_DataType_UINT16) && + constant_initializer) { + const Node& consumer_node = *node->OutputNodesBegin(); + selection_node_set.insert(index); + consumer_to_dq[consumer_node.Index()] = index; + LOGS_DEFAULT(VERBOSE) << "[TensorRT EP] " << consumer_node.Name() << " <- " << node->Name(); + } + } + LOGS_DEFAULT(VERBOSE) << "[TensorRT EP] Total " << selection_node_set.size() << " DequantizeLinear node(s) are selected."; +} + +/** + * This function returns an optimization ComputeCapability that is limited to: + * 1. the DQ nodes in this individual TRT ComputeCapability + * 2. the DQ nodes that are qualified and selected by TRT EP + * + * It also needs to make sure the DQ nodes is a subset of the complete list of DQ nodes to optimize in original selection ComputeCapability. + * Finally, copy the optimization function from the original selection ComputeCapability. + */ +std::unique_ptr TensorrtExecutionProvider::CreateOptimizationComputeCapability(ComputeCapability* selection_cc, + std::unordered_set& trt_selection_node_set, + ComputeCapability* trt_cc) const { + auto sub_graph = onnxruntime::IndexedSubGraph::Create(); + std::unordered_set selection_node_set; + + for (auto index : selection_cc->SubGraph()->Nodes()) { + selection_node_set.insert(index); + } + + for (auto index : trt_cc->SubGraph()->Nodes()) { + if (selection_node_set.find(index) == selection_node_set.end()) { + continue; + } + if (trt_selection_node_set.find(index) == trt_selection_node_set.end()) { + continue; + } + sub_graph->Nodes().push_back(index); + } + auto compute_capability = ComputeCapability::Create(std::move(sub_graph)); + compute_capability->copy_optimization_func(selection_cc); + return compute_capability; +} + +/** + * This function helps add back the DQ nodes that are filtered out by TRT parser. + * The reason is the DQ nodes can be optimized and dequantized by applying ConstantFoldingDQ optimizer by ORT L2+ optimization. + */ +void TensorrtExecutionProvider::UpdateSupportedNodeVectorForDQ(const GraphViewer& graph, + SubGraph_t& supported_node_vector, + SubGraphCollection_t& supported_nodes_vector, + std::unordered_map consumer_to_dq) const { + if (consumer_to_dq.empty()) { + return; + } + + if (!supported_node_vector.second) { + return; + } + + const std::vector& node_index = graph.GetNodesInTopologicalOrder(1); + auto supported_nodes = supported_node_vector.first; + for (auto index : supported_nodes) { + if (consumer_to_dq.find(node_index[index]) == consumer_to_dq.end()) { + continue; + } + + auto dq_node_index = consumer_to_dq[node_index[index]]; + + // Check if DQ node is included in one of the subgraphs + auto in_the_subgraph_collection = [&](NodeIndex node_idx) -> bool { + for (auto& node_vector : supported_nodes_vector) { + if (!node_vector.second) { + continue; + } + for (auto i : node_vector.first) { + if (node_index[i] == node_idx) { + return true; + } + } + } + return false; + }; + + // If the DQ node is already in the subgraph, do nothing. + if (in_the_subgraph_collection(dq_node_index)) { + continue; + } + + // Find the iterator pointing to the target element + auto it = std::find(node_index.begin(), node_index.end(), dq_node_index); + if (it != node_index.end()) { + // Calculate the index + size_t idx = std::distance(node_index.begin(), it); + supported_node_vector.first.push_back(idx); + auto node = graph.GetNode(dq_node_index); + LOGS_DEFAULT(VERBOSE) << "[TensorRT EP] " << node->Name() << " is included which is filtered out by TRT parser."; + } + } +} } // namespace onnxruntime diff --git a/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider_info.cc b/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider_info.cc index bc0d00ec6791f..ace5bbe65fc24 100644 --- a/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider_info.cc +++ b/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider_info.cc @@ -57,6 +57,7 @@ constexpr const char* kEngineHwCompatible = "trt_engine_hw_compatible"; constexpr const char* kONNXBytestream = "trt_onnx_bytestream"; constexpr const char* kONNXBytestreamSize = "trt_onnx_bytestream_size"; constexpr const char* kOpTypesToExclude = "trt_op_types_to_exclude"; +constexpr const char* kPreviewFeatures = "trt_preview_features"; } // namespace provider_option_names } // namespace tensorrt @@ -136,6 +137,7 @@ TensorrtExecutionProviderInfo TensorrtExecutionProviderInfo::FromProviderOptions }) .AddAssignmentToReference(tensorrt::provider_option_names::kONNXBytestreamSize, info.onnx_bytestream_size) .AddAssignmentToReference(tensorrt::provider_option_names::kOpTypesToExclude, info.op_types_to_exclude) + .AddAssignmentToReference(tensorrt::provider_option_names::kPreviewFeatures, info.preview_features) .Parse(options)); // add new provider option here. info.user_compute_stream = user_compute_stream; @@ -191,6 +193,7 @@ ProviderOptions TensorrtExecutionProviderInfo::ToProviderOptions(const TensorrtE {tensorrt::provider_option_names::kONNXBytestream, MakeStringWithClassicLocale(info.onnx_bytestream)}, {tensorrt::provider_option_names::kONNXBytestreamSize, MakeStringWithClassicLocale(info.onnx_bytestream_size)}, {tensorrt::provider_option_names::kOpTypesToExclude, MakeStringWithClassicLocale(info.op_types_to_exclude)}, + {tensorrt::provider_option_names::kPreviewFeatures, MakeStringWithClassicLocale(info.preview_features)}, }; return options; } @@ -361,5 +364,6 @@ void TensorrtExecutionProviderInfo::UpdateProviderOptions(void* provider_options trt_provider_options_v2.trt_onnx_bytestream = internal_options.onnx_bytestream; trt_provider_options_v2.trt_onnx_bytestream_size = internal_options.onnx_bytestream_size; trt_provider_options_v2.trt_op_types_to_exclude = copy_string_if_needed(internal_options.op_types_to_exclude); + trt_provider_options_v2.trt_preview_features = copy_string_if_needed(internal_options.preview_features); } } // namespace onnxruntime diff --git a/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider_info.h b/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider_info.h index a6fda73b55529..139319829c210 100644 --- a/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider_info.h +++ b/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider_info.h @@ -61,6 +61,7 @@ struct TensorrtExecutionProviderInfo { std::string engine_cache_prefix{""}; bool engine_hw_compatible{false}; std::string op_types_to_exclude{""}; + std::string preview_features{""}; static TensorrtExecutionProviderInfo FromProviderOptions(const ProviderOptions& options); static ProviderOptions ToProviderOptions(const TensorrtExecutionProviderInfo& info); diff --git a/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider_utils.h b/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider_utils.h index 5a7b135fd92cd..dcf3673a004e4 100644 --- a/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider_utils.h +++ b/onnxruntime/core/providers/tensorrt/tensorrt_execution_provider_utils.h @@ -533,7 +533,7 @@ HashValue TRTGenerateId(const GraphViewer& graph_viewer, std::string trt_version uint32_t hash[4] = {0, 0, 0, 0}; auto hash_str = [&hash](const std::string& str) { - MurmurHash3::x86_128(str.data(), gsl::narrow_cast(str.size()), hash[0], &hash); + MurmurHash3::x86_128(str.data(), str.size(), hash[0], &hash); }; // Use the model's file name instead of the entire path to avoid cache regeneration if path changes diff --git a/onnxruntime/core/providers/tensorrt/tensorrt_provider_factory.cc b/onnxruntime/core/providers/tensorrt/tensorrt_provider_factory.cc index e4521ddd18ade..0d2e88d17519c 100644 --- a/onnxruntime/core/providers/tensorrt/tensorrt_provider_factory.cc +++ b/onnxruntime/core/providers/tensorrt/tensorrt_provider_factory.cc @@ -119,6 +119,7 @@ struct Tensorrt_Provider : Provider { info.onnx_bytestream = options.trt_onnx_bytestream; info.onnx_bytestream_size = options.trt_onnx_bytestream_size; info.op_types_to_exclude = options.trt_op_types_to_exclude == nullptr ? "" : options.trt_op_types_to_exclude; + info.preview_features = options.trt_preview_features == nullptr ? "" : options.trt_preview_features; return std::make_shared(info); } diff --git a/onnxruntime/core/providers/vitisai/imp/global_api.cc b/onnxruntime/core/providers/vitisai/imp/global_api.cc index f67cd28137d4d..33aa8fa2b31b8 100644 --- a/onnxruntime/core/providers/vitisai/imp/global_api.cc +++ b/onnxruntime/core/providers/vitisai/imp/global_api.cc @@ -49,6 +49,8 @@ struct OrtVitisAIEpAPI { const std::string& model_path, const onnxruntime::Graph& graph, const onnxruntime::ProviderOptions& options); std::vector>* (*compile_onnx_model_vitisai_ep_with_error_handling)( const std::string& model_path, const onnxruntime::Graph& graph, const onnxruntime::ProviderOptions& options, void* status, vaip_core::error_report_func func); + std::vector>* (*compile_onnx_model_vitisai_ep_v3)( + const std::filesystem::path& model_path, const onnxruntime::Graph& graph, const onnxruntime::ProviderOptions& options, void* status, vaip_core::error_report_func func); uint32_t (*vaip_get_version)(); void (*create_ep_context_nodes)( const std::vector>& eps, @@ -82,7 +84,8 @@ struct OrtVitisAIEpAPI { ORT_THROW_IF_ERROR(env.GetSymbolFromLibrary(handle_, "initialize_onnxruntime_vitisai_ep", (void**)&initialize_onnxruntime_vitisai_ep)); auto status1 = env.GetSymbolFromLibrary(handle_, "compile_onnx_model_vitisai_ep_with_error_handling", (void**)&compile_onnx_model_vitisai_ep_with_error_handling); auto status2 = env.GetSymbolFromLibrary(handle_, "compile_onnx_model_vitisai_ep_with_options", (void**)&compile_onnx_model_with_options); - if ((!status1.IsOK()) && (!status2.IsOK())) { + auto status3 = env.GetSymbolFromLibrary(handle_, "compile_onnx_model_vitisai_ep_v3", (void**)&compile_onnx_model_vitisai_ep_v3); + if ((!status1.IsOK()) && (!status2.IsOK()) && (!status3.IsOK())) { ::onnxruntime::LogRuntimeError(0, status2, __FILE__, static_cast(__FUNCTION__), __LINE__); ORT_THROW(status2); } @@ -129,17 +132,25 @@ void change_status_with_error(void* status_ptr, int error_code, const char* erro vaip_core::DllSafe>> compile_onnx_model( const onnxruntime::GraphViewer& graph_viewer, const onnxruntime::logging::Logger& logger, const onnxruntime::ProviderOptions& options) { - auto model_path = graph_viewer.ModelPath().string(); - if (s_library_vitisaiep.compile_onnx_model_vitisai_ep_with_error_handling) { + auto model_path = graph_viewer.ModelPath(); + if (s_library_vitisaiep.compile_onnx_model_vitisai_ep_v3) { Status status = Status::OK(); auto status_ptr = reinterpret_cast(&status); - auto ret = vaip_core::DllSafe(s_library_vitisaiep.compile_onnx_model_vitisai_ep_with_error_handling(model_path, graph_viewer.GetGraph(), options, status_ptr, change_status_with_error)); + auto ret = vaip_core::DllSafe(s_library_vitisaiep.compile_onnx_model_vitisai_ep_v3(model_path, graph_viewer.GetGraph(), options, status_ptr, change_status_with_error)); + if (!status.IsOK()) { + ORT_THROW(status); + } + return ret; + } else if (s_library_vitisaiep.compile_onnx_model_vitisai_ep_with_error_handling) { + Status status = Status::OK(); + auto status_ptr = reinterpret_cast(&status); + auto ret = vaip_core::DllSafe(s_library_vitisaiep.compile_onnx_model_vitisai_ep_with_error_handling(model_path.u8string(), graph_viewer.GetGraph(), options, status_ptr, change_status_with_error)); if (!status.IsOK()) { ORT_THROW(status); } return ret; } else { - return vaip_core::DllSafe(s_library_vitisaiep.compile_onnx_model_with_options(model_path, graph_viewer.GetGraph(), options)); + return vaip_core::DllSafe(s_library_vitisaiep.compile_onnx_model_with_options(model_path.u8string(), graph_viewer.GetGraph(), options)); } } @@ -349,10 +360,19 @@ vaip_core::OrtApiForVaip* create_org_api_hook() { }; the_global_api.graph_nodes_unsafe = [](const Graph& graph) -> auto { return vaip_core::DllSafe(graph.Nodes()); }; the_global_api.graph_get_name = [](const Graph& graph) -> const std::string& { return graph.Name(); }; + the_global_api.graph_set_name = [](Graph& graph, const char* name) -> void { return graph.SetName(std::string(name)); }; the_global_api.graph_reverse_dfs_from = [](const Graph& graph, gsl::span from, const auto& enter, const auto& leave, const auto& stop) { graph.ReverseDFSFrom(from, enter, leave, nullptr, stop); }; + + the_global_api.graph_infer_shapes_from_filepath = [](const std::string& m, const std::string& save_path) -> auto { return Provider_GetHost()->InferShapes(m, save_path); }; + the_global_api.graph_to_graph_proto = [](const Graph& graph) -> ONNX_NAMESPACE::GraphProto* { + return graph.ToGraphProto().release(); + }; + the_global_api.graph_proto_delete = [](ONNX_NAMESPACE::GraphProto* p) { delete p; }; + the_global_api.graph_infer_shapes = [](ONNX_NAMESPACE::ModelProto& m) -> auto { return Provider_GetHost()->InferShapes(m); }; + // node the_global_api.node_get_inputs_unsafe = vaip::node_get_inputs; the_global_api.node_get_output_node_args_unsafe = vaip::node_get_output_node_args; diff --git a/onnxruntime/core/providers/vitisai/include/vaip/my_ort.h b/onnxruntime/core/providers/vitisai/include/vaip/my_ort.h index 85a1262d8489b..6c9c728d8ffad 100644 --- a/onnxruntime/core/providers/vitisai/include/vaip/my_ort.h +++ b/onnxruntime/core/providers/vitisai/include/vaip/my_ort.h @@ -20,6 +20,7 @@ struct NodeAttributes; namespace ONNX_NAMESPACE { struct AttributeProto; struct TensorProto; +struct GraphProto; struct ModelProto; #ifndef USE_VITISAI enum TensorProto_DataType : int { @@ -71,6 +72,7 @@ enum AttributeProto_AttributeType : int { namespace vaip_core { class GraphHolder; using ONNX_NAMESPACE::AttributeProto; +using ONNX_NAMESPACE::GraphProto; using ONNX_NAMESPACE::ModelProto; using ONNX_NAMESPACE::TensorProto; using onnxruntime::Graph; diff --git a/onnxruntime/core/providers/vitisai/include/vaip/vaip_ort_api.h b/onnxruntime/core/providers/vitisai/include/vaip/vaip_ort_api.h index 0becc41d861f7..d40da70726b43 100644 --- a/onnxruntime/core/providers/vitisai/include/vaip/vaip_ort_api.h +++ b/onnxruntime/core/providers/vitisai/include/vaip/vaip_ort_api.h @@ -13,7 +13,7 @@ struct OrtApi; namespace vaip_core { -#define VAIP_ORT_API_MAJOR (14u) +#define VAIP_ORT_API_MAJOR (16u) #define VAIP_ORT_API_MINOR (0u) #define VAIP_ORT_API_PATCH (0u) struct OrtApiForVaip { @@ -249,7 +249,13 @@ struct OrtApiForVaip { const std::function& leave, const std::function& comp, const std::function& - stop); // [103] + stop); // [103] + void (*graph_set_name)(Graph& graph, const char* name); // [104] + void (*graph_infer_shapes_from_filepath)( + const std::string& m, const std::string& save_path); // [105] + GraphProto* (*graph_to_graph_proto)(const Graph& graph); // [106] + void (*graph_proto_delete)(GraphProto* p); // [107] + void (*graph_infer_shapes)(ModelProto& m); // [108] }; #ifndef USE_VITISAI diff --git a/onnxruntime/core/providers/vitisai/vitisai_execution_provider.cc b/onnxruntime/core/providers/vitisai/vitisai_execution_provider.cc index 5d2204b0b1979..ab8a95b38491d 100644 --- a/onnxruntime/core/providers/vitisai/vitisai_execution_provider.cc +++ b/onnxruntime/core/providers/vitisai/vitisai_execution_provider.cc @@ -51,7 +51,7 @@ const InlinedVector VitisAIExecutionProvider::GetEpContextNodes() c return ep_context_node_ptrs; } std::vector> VitisAIExecutionProvider::GetCapability( - const onnxruntime::GraphViewer& graph_viewer, const IKernelLookup& kernel_lookup, IResourceAccountant* /* resource_accountant */) const { + const onnxruntime::GraphViewer& graph_viewer, const IKernelLookup& kernel_lookup, const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const { if (graph_viewer.IsSubgraph()) { // VITIS AI EP not support sungraph. Assigned to CPU. return {}; diff --git a/onnxruntime/core/providers/vitisai/vitisai_execution_provider.h b/onnxruntime/core/providers/vitisai/vitisai_execution_provider.h index 5b031ab882839..f72f8cc721fbd 100644 --- a/onnxruntime/core/providers/vitisai/vitisai_execution_provider.h +++ b/onnxruntime/core/providers/vitisai/vitisai_execution_provider.h @@ -29,6 +29,7 @@ class VitisAIExecutionProvider : public IExecutionProvider { std::vector> GetCapability(const onnxruntime::GraphViewer& graph_viewer, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const override; int GetDeviceId() const { return 0; } diff --git a/onnxruntime/core/providers/vsinpu/vsinpu_execution_provider.cc b/onnxruntime/core/providers/vsinpu/vsinpu_execution_provider.cc index 4b9f6fae86423..3b5daef04dd50 100644 --- a/onnxruntime/core/providers/vsinpu/vsinpu_execution_provider.cc +++ b/onnxruntime/core/providers/vsinpu/vsinpu_execution_provider.cc @@ -62,6 +62,7 @@ VSINPUExecutionProvider::~VSINPUExecutionProvider() {} std::vector> VSINPUExecutionProvider::GetCapability(const onnxruntime::GraphViewer& graph_viewer, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const { std::vector> result; diff --git a/onnxruntime/core/providers/vsinpu/vsinpu_execution_provider.h b/onnxruntime/core/providers/vsinpu/vsinpu_execution_provider.h index 16cfbc8a9c581..1c0b8b63a8e6c 100644 --- a/onnxruntime/core/providers/vsinpu/vsinpu_execution_provider.h +++ b/onnxruntime/core/providers/vsinpu/vsinpu_execution_provider.h @@ -40,6 +40,7 @@ class VSINPUExecutionProvider : public IExecutionProvider { std::vector> GetCapability( const onnxruntime::GraphViewer& graph_viewer, const IKernelLookup& kernel_lookup, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const override; std::shared_ptr GetKernelRegistry() const override; Status Compile(const std::vector& fused_nodes_and_graphs, diff --git a/onnxruntime/core/providers/webgpu/allocator.cc b/onnxruntime/core/providers/webgpu/allocator.cc index 51a06ad7643f6..315d0cd75e946 100644 --- a/onnxruntime/core/providers/webgpu/allocator.cc +++ b/onnxruntime/core/providers/webgpu/allocator.cc @@ -13,10 +13,15 @@ void* GpuBufferAllocator::Alloc(size_t size) { return nullptr; } - auto buffer = context_.BufferManager().Create(size); - stats_.num_allocs++; - return buffer; + +#if !defined(__wasm__) + if (!session_initialized_ && context_.DeviceHasFeature(wgpu::FeatureName::BufferMapExtendedUsages)) { + return context_.BufferManager().CreateUMA(size); + } +#endif // !defined(__wasm__) + + return context_.BufferManager().Create(size); } void GpuBufferAllocator::Free(void* p) { @@ -30,5 +35,9 @@ void GpuBufferAllocator::GetStats(AllocatorStats* stats) { *stats = stats_; } +void GpuBufferAllocator::OnSessionInitializationEnd() { + session_initialized_ = true; +} + } // namespace webgpu } // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/allocator.h b/onnxruntime/core/providers/webgpu/allocator.h index 51ca65a8b4822..d98661884c659 100644 --- a/onnxruntime/core/providers/webgpu/allocator.h +++ b/onnxruntime/core/providers/webgpu/allocator.h @@ -25,9 +25,12 @@ class GpuBufferAllocator : public IAllocator { virtual void Free(void* p) override; void GetStats(AllocatorStats* stats) override; + void OnSessionInitializationEnd(); + private: AllocatorStats stats_; const WebGpuContext& context_; + bool session_initialized_ = false; }; } // namespace webgpu diff --git a/onnxruntime/core/providers/webgpu/buffer_manager.cc b/onnxruntime/core/providers/webgpu/buffer_manager.cc index de71566324efd..1d8c689cbd909 100644 --- a/onnxruntime/core/providers/webgpu/buffer_manager.cc +++ b/onnxruntime/core/providers/webgpu/buffer_manager.cc @@ -7,10 +7,20 @@ namespace onnxruntime { namespace webgpu { +namespace { + constexpr size_t NormalizeBufferSize(size_t size) { return (size + 15) / 16 * 16; } +void EnforceBufferUnmapped(WebGpuContext& context, WGPUBuffer buffer) { + if (context.ValidationMode() > ValidationMode::Basic) { + ORT_ENFORCE(wgpuBufferGetMapState(buffer) == WGPUBufferMapState_Unmapped, "Buffer is still mapped."); + } +} + +} // namespace + class DisabledCacheManager : public IBufferCacheManager { size_t CalculateBufferSize(size_t request_size) override { return NormalizeBufferSize(request_size); @@ -46,14 +56,27 @@ class LazyReleaseCacheManager : public IBufferCacheManager { } void ReleaseBuffer(WGPUBuffer buffer) override { - pending_buffers_.emplace_back(wgpu::Buffer::Acquire(buffer)); + pending_buffers_.emplace_back(buffer); } void OnRefresh() override { + Release(); pending_buffers_.clear(); } - std::vector pending_buffers_; + public: + ~LazyReleaseCacheManager() { + Release(); + } + + protected: + void Release() { + for (auto& buffer : pending_buffers_) { + wgpuBufferRelease(buffer); + } + } + + std::vector pending_buffers_; }; class SimpleCacheManager : public IBufferCacheManager { @@ -64,7 +87,7 @@ class SimpleCacheManager : public IBufferCacheManager { WGPUBuffer TryAcquireCachedBuffer(size_t buffer_size) override { auto it = buffers_.find(buffer_size); if (it != buffers_.end() && !it->second.empty()) { - auto buffer = it->second.back().MoveToCHandle(); + auto buffer = it->second.back(); it->second.pop_back(); return buffer; } @@ -77,18 +100,31 @@ class SimpleCacheManager : public IBufferCacheManager { } void ReleaseBuffer(WGPUBuffer buffer) override { - pending_buffers_.emplace_back(wgpu::Buffer::Acquire(buffer)); + pending_buffers_.emplace_back(buffer); } void OnRefresh() override { for (auto& buffer : pending_buffers_) { - buffers_[static_cast(buffer.GetSize())].emplace_back(std::move(buffer)); + buffers_[static_cast(wgpuBufferGetSize(buffer))].emplace_back(buffer); } pending_buffers_.clear(); } - std::map> buffers_; - std::vector pending_buffers_; + public: + ~SimpleCacheManager() { + for (auto& buffer : pending_buffers_) { + wgpuBufferRelease(buffer); + } + for (auto& pair : buffers_) { + for (auto& buffer : pair.second) { + wgpuBufferRelease(buffer); + } + } + } + + protected: + std::map> buffers_; + std::vector pending_buffers_; }; // TODO: maybe use different bucket size for storage and uniform buffers? @@ -145,7 +181,7 @@ class BucketCacheManager : public IBufferCacheManager { WGPUBuffer TryAcquireCachedBuffer(size_t buffer_size) override { auto it = buckets_.find(buffer_size); if (it != buckets_.end() && !it->second.empty()) { - auto buffer = it->second.back().MoveToCHandle(); + auto buffer = it->second.back(); it->second.pop_back(); return buffer; } @@ -157,31 +193,44 @@ class BucketCacheManager : public IBufferCacheManager { } void ReleaseBuffer(WGPUBuffer buffer) override { - pending_buffers_.emplace_back(wgpu::Buffer::Acquire(buffer)); + pending_buffers_.emplace_back(buffer); } void OnRefresh() override { // TODO: consider graph capture. currently not supported for (auto& buffer : pending_buffers_) { - auto buffer_size = static_cast(buffer.GetSize()); + auto buffer_size = static_cast(wgpuBufferGetSize(buffer)); auto it = buckets_.find(buffer_size); if (it != buckets_.end() && it->second.size() < buckets_limit_[buffer_size]) { - it->second.emplace_back(std::move(buffer)); + it->second.emplace_back(buffer); + } else { + wgpuBufferRelease(buffer); } } pending_buffers_.clear(); } + ~BucketCacheManager() { + for (auto& buffer : pending_buffers_) { + wgpuBufferRelease(buffer); + } + for (auto& pair : buckets_) { + for (auto& buffer : pair.second) { + wgpuBufferRelease(buffer); + } + } + } + protected: void Initialize() { buckets_keys_.reserve(buckets_limit_.size()); buckets_.reserve(buckets_limit_.size()); for (const auto& pair : buckets_limit_) { buckets_keys_.push_back(pair.first); - buckets_.emplace(pair.first, std::vector()); + buckets_.emplace(pair.first, std::vector()); } std::sort(buckets_keys_.begin(), buckets_keys_.end()); @@ -195,8 +244,8 @@ class BucketCacheManager : public IBufferCacheManager { #endif } std::unordered_map buckets_limit_; - std::unordered_map> buckets_; - std::vector pending_buffers_; + std::unordered_map> buckets_; + std::vector pending_buffers_; std::vector buckets_keys_; }; @@ -244,6 +293,15 @@ BufferManager::BufferManager(WebGpuContext& context, BufferCacheMode storage_buf } void BufferManager::Upload(void* src, WGPUBuffer dst, size_t size) { + // If the buffer is mapped, we can directly write to it. + void* mapped_data = wgpuBufferGetMappedRange(dst, 0, WGPU_WHOLE_MAP_SIZE); // ensure the buffer is mapped + if (mapped_data) { + memcpy(mapped_data, src, size); + wgpuBufferUnmap(dst); + return; + } + + // Otherwise, we need to use a staging buffer to upload data. auto buffer_size = NormalizeBufferSize(size); wgpu::BufferDescriptor desc{}; @@ -252,23 +310,27 @@ void BufferManager::Upload(void* src, WGPUBuffer dst, size_t size) { desc.mappedAtCreation = true; auto staging_buffer = context_.Device().CreateBuffer(&desc); - auto mapped_data = staging_buffer.GetMappedRange(); + mapped_data = staging_buffer.GetMappedRange(); memcpy(mapped_data, src, size); staging_buffer.Unmap(); auto& command_encoder = context_.GetCommandEncoder(); context_.EndComputePass(); command_encoder.CopyBufferToBuffer(staging_buffer, 0, dst, 0, buffer_size); - pending_staging_buffers_.push_back(staging_buffer); + context_.Flush(); } void BufferManager::MemCpy(WGPUBuffer src, WGPUBuffer dst, size_t size) { ORT_ENFORCE(src != dst, "Source and destination buffers must be different."); + EnforceBufferUnmapped(context_, src); + EnforceBufferUnmapped(context_, dst); auto buffer_size = NormalizeBufferSize(size); - ORT_ENFORCE(buffer_size <= wgpuBufferGetSize(src) && buffer_size <= wgpuBufferGetSize(dst), + auto src_size = static_cast(wgpuBufferGetSize(src)); + auto dst_size = static_cast(wgpuBufferGetSize(dst)); + ORT_ENFORCE(buffer_size <= src_size && buffer_size <= dst_size, "Source and destination buffers must have enough space for the copy operation. src_size=", - wgpuBufferGetSize(src), ", dst_size=", wgpuBufferGetSize(dst), ", copy_size=", buffer_size, "."); + src_size, ", dst_size=", dst_size, ", copy_size=", buffer_size, "."); auto& command_encoder = context_.GetCommandEncoder(); context_.EndComputePass(); @@ -276,7 +338,7 @@ void BufferManager::MemCpy(WGPUBuffer src, WGPUBuffer dst, size_t size) { } WGPUBuffer BufferManager::Create(size_t size, wgpu::BufferUsage usage) { - auto& cache = GetCacheManager(static_cast(usage)); + auto& cache = GetCacheManager(usage); auto buffer_size = cache.CalculateBufferSize(size); auto buffer = cache.TryAcquireCachedBuffer(buffer_size); @@ -288,7 +350,6 @@ WGPUBuffer BufferManager::Create(size_t size, wgpu::BufferUsage usage) { wgpu::BufferDescriptor desc{}; desc.size = buffer_size; desc.usage = usage; - // desc.label = std::to_string(xx++).c_str(); buffer = context_.Device().CreateBuffer(&desc).MoveToCHandle(); ORT_ENFORCE(buffer, "Failed to create GPU buffer: size=", buffer_size, ", usage=", uint64_t(usage), "."); @@ -297,11 +358,33 @@ WGPUBuffer BufferManager::Create(size_t size, wgpu::BufferUsage usage) { return buffer; } +WGPUBuffer BufferManager::CreateUMA(size_t size, wgpu::BufferUsage usage) { + ORT_ENFORCE(usage & wgpu::BufferUsage::Storage, "UMA buffer must be a storage buffer."); + auto& cache = GetCacheManager(usage); + auto buffer_size = cache.CalculateBufferSize(size); + + // Ensure the buffer is mapped for writing at creation. + usage |= wgpu::BufferUsage::MapWrite; + + wgpu::BufferDescriptor desc{}; + desc.size = buffer_size; + desc.usage = usage; + desc.mappedAtCreation = true; + auto buffer = context_.Device().CreateBuffer(&desc).MoveToCHandle(); + + ORT_ENFORCE(buffer, "Failed to create GPU buffer: size=", buffer_size, ", usage=", uint64_t(usage), "."); + + cache.RegisterBuffer(buffer, size); + return buffer; +} + void BufferManager::Release(WGPUBuffer buffer) { + EnforceBufferUnmapped(context_, buffer); GetCacheManager(buffer).ReleaseBuffer(buffer); } void BufferManager::Download(WGPUBuffer src, void* dst, size_t size) { + EnforceBufferUnmapped(context_, src); auto buffer_size = NormalizeBufferSize(size); wgpu::BufferDescriptor desc{}; @@ -325,19 +408,18 @@ void BufferManager::Download(WGPUBuffer src, void* dst, size_t size) { } void BufferManager::RefreshPendingBuffers() { - pending_staging_buffers_.clear(); storage_cache_->OnRefresh(); uniform_cache_->OnRefresh(); query_resolve_cache_->OnRefresh(); default_cache_->OnRefresh(); } -IBufferCacheManager& BufferManager::GetCacheManager(WGPUBufferUsage usage) const { - if (usage & WGPUBufferUsage_Storage) { +IBufferCacheManager& BufferManager::GetCacheManager(wgpu::BufferUsage usage) const { + if (usage & wgpu::BufferUsage::Storage) { return *storage_cache_; - } else if (usage & WGPUBufferUsage_Uniform) { + } else if (usage & wgpu::BufferUsage::Uniform) { return *uniform_cache_; - } else if (usage & WGPUBufferUsage_QueryResolve) { + } else if (usage & wgpu::BufferUsage::QueryResolve) { return *query_resolve_cache_; } else { return *default_cache_; @@ -345,7 +427,8 @@ IBufferCacheManager& BufferManager::GetCacheManager(WGPUBufferUsage usage) const } IBufferCacheManager& BufferManager::GetCacheManager(WGPUBuffer buffer) const { - return GetCacheManager(wgpuBufferGetUsage(buffer)); + auto usage = static_cast(wgpuBufferGetUsage(buffer)); + return GetCacheManager(usage); } std::unique_ptr BufferManagerFactory::Create(WebGpuContext& context, BufferCacheMode storage_buffer_cache_mode, BufferCacheMode uniform_buffer_cache_mode, BufferCacheMode query_resolve_buffer_cache_mode) { diff --git a/onnxruntime/core/providers/webgpu/buffer_manager.h b/onnxruntime/core/providers/webgpu/buffer_manager.h index 20bee52835c02..b9028ad5de858 100644 --- a/onnxruntime/core/providers/webgpu/buffer_manager.h +++ b/onnxruntime/core/providers/webgpu/buffer_manager.h @@ -5,7 +5,7 @@ #include -#include +#include "core/providers/webgpu/webgpu_external_header.h" #include "core/framework/execution_provider.h" @@ -62,12 +62,15 @@ class BufferManager { void Upload(void* src, WGPUBuffer dst, size_t size); void MemCpy(WGPUBuffer src, WGPUBuffer dst, size_t size); WGPUBuffer Create(size_t size, wgpu::BufferUsage usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst); + // Create a buffer mapped for writing. + WGPUBuffer CreateUMA(size_t size, wgpu::BufferUsage usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc | + wgpu::BufferUsage::CopyDst); void Release(WGPUBuffer buffer); void Download(WGPUBuffer src, void* dst, size_t size); void RefreshPendingBuffers(); private: - IBufferCacheManager& GetCacheManager(WGPUBufferUsage usage) const; + IBufferCacheManager& GetCacheManager(wgpu::BufferUsage usage) const; IBufferCacheManager& GetCacheManager(WGPUBuffer buffer) const; WebGpuContext& context_; @@ -75,8 +78,6 @@ class BufferManager { std::unique_ptr uniform_cache_; std::unique_ptr query_resolve_cache_; std::unique_ptr default_cache_; - - std::vector pending_staging_buffers_; }; class BufferManagerFactory { diff --git a/onnxruntime/core/providers/webgpu/compute_context.h b/onnxruntime/core/providers/webgpu/compute_context.h index 680e03aef0aa3..3117208c7be7d 100644 --- a/onnxruntime/core/providers/webgpu/compute_context.h +++ b/onnxruntime/core/providers/webgpu/compute_context.h @@ -3,7 +3,7 @@ #pragma once -#include +#include "core/providers/webgpu/webgpu_external_header.h" #include @@ -37,8 +37,8 @@ class ComputeContext { inline const wgpu::Limits& DeviceLimits() const { return webgpu_context_.DeviceLimits(); } - inline const wgpu::Device& Device() const { - return webgpu_context_.Device(); + inline bool HasFeature(wgpu::FeatureName feature) const { + return webgpu_context_.DeviceHasFeature(feature); } // diff --git a/onnxruntime/core/providers/webgpu/controlflow/if.cc b/onnxruntime/core/providers/webgpu/controlflow/if.cc new file mode 100644 index 0000000000000..233d1f760383f --- /dev/null +++ b/onnxruntime/core/providers/webgpu/controlflow/if.cc @@ -0,0 +1,77 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/webgpu/controlflow/if.h" + +using namespace ONNX_NAMESPACE; +using namespace onnxruntime::common; + +namespace onnxruntime { +namespace webgpu { + +ONNX_OPERATOR_VERSIONED_KERNEL_EX(If, + kOnnxDomain, + 1, 10, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .InputMemoryType(OrtMemTypeCPUInput, 0) // 'cond' needs to be on CPU + .TypeConstraint("B", DataTypeImpl::GetTensorType()) + .TypeConstraint("V", DataTypeImpl::AllFixedSizeTensorTypes()), + If); +// output shape rules requiring the output shapes of the 'THEN' and 'ELSE' +// branches to be the same were relaxed in opset-11 +ONNX_OPERATOR_VERSIONED_KERNEL_EX(If, + kOnnxDomain, + 11, 12, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .InputMemoryType(OrtMemTypeCPUInput, 0) // 'cond' needs to be on CPU + .TypeConstraint("B", DataTypeImpl::GetTensorType()) + .TypeConstraint("V", DataTypeImpl::AllFixedSizeTensorTypes()), + If); + +// opset-13 supports sequence type for If's subgraph outputs +ONNX_OPERATOR_VERSIONED_KERNEL_EX(If, + kOnnxDomain, + 13, 18, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .InputMemoryType(OrtMemTypeCPUInput, 0) // 'cond' needs to be on CPU + .TypeConstraint("B", DataTypeImpl::GetTensorType()) + // Support sequence/optional tensors when all WebGPU infra + // (including tests runner) supports it + .TypeConstraint("V", DataTypeImpl::AllFixedSizeTensorTypes()), + If); + +// opset-19 supports float8 +ONNX_OPERATOR_VERSIONED_KERNEL_EX(If, + kOnnxDomain, + 19, 20, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .InputMemoryType(OrtMemTypeCPUInput, 0) // 'cond' needs to be on CPU + .TypeConstraint("B", DataTypeImpl::GetTensorType()) + // Support sequence/optional tensors when all WebGPU infra + // (including tests runner) supports it + .TypeConstraint("V", DataTypeImpl::AllFixedSizeTensorTypes()), + If); + +ONNX_OPERATOR_KERNEL_EX(If, + kOnnxDomain, + 21, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .InputMemoryType(OrtMemTypeCPUInput, 0) // 'cond' needs to be on CPU + .TypeConstraint("B", DataTypeImpl::GetTensorType()) + // Support sequence/optional tensors when all WebGPU infra + // (including tests runner) supports it + .TypeConstraint("V", DataTypeImpl::AllFixedSizeTensorTypes()), + If); + +Status If::Compute(OpKernelContext* ctx) const { + // call the base CPU version. + return onnxruntime::If::Compute(ctx); +} + +} // namespace webgpu +} // namespace onnxruntime \ No newline at end of file diff --git a/onnxruntime/core/providers/webgpu/controlflow/if.h b/onnxruntime/core/providers/webgpu/controlflow/if.h new file mode 100644 index 0000000000000..0755c5d33d7a3 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/controlflow/if.h @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/webgpu/webgpu_kernel.h" +#include "core/common/common.h" +#include "core/providers/cpu/controlflow/if.h" + +namespace onnxruntime { +namespace webgpu { + +// Use the CPU implementation for the logic +class If final : public onnxruntime::If { + public: + If(const OpKernelInfo& info) : onnxruntime::If(info) {} + + Status Compute(OpKernelContext* ctx) const override; +}; + +} // namespace webgpu +} // namespace onnxruntime \ No newline at end of file diff --git a/onnxruntime/core/providers/webgpu/external_data_loader.cc b/onnxruntime/core/providers/webgpu/external_data_loader.cc new file mode 100644 index 0000000000000..6da9598b146f5 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/external_data_loader.cc @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if defined(__wasm__) + +#include + +#include "core/framework/tensor.h" +#include "core/providers/webgpu/external_data_loader.h" + +namespace onnxruntime { +namespace webgpu { + +bool ExternalDataLoader::CanLoad(const OrtMemoryInfo& target_memory_info) const { + return target_memory_info.device.Type() == OrtDevice::CPU || + (target_memory_info.device.Type() == OrtDevice::GPU && target_memory_info.name == WEBGPU_BUFFER); +} + +common::Status ExternalDataLoader::LoadTensor(const Env& env, + const std::filesystem::path& data_file_path, + FileOffsetType data_offset, + SafeInt data_length, + Tensor& tensor) const { + ExternalDataLoadType load_type; + if (tensor.Location().device.Type() == OrtDevice::CPU) { + load_type = ExternalDataLoadType::CPU; + } else if (tensor.Location().device.Type() == OrtDevice::GPU && + tensor.Location().name == WEBGPU_BUFFER) { + load_type = ExternalDataLoadType::WEBGPU_BUFFER; + } else { + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Unsupported tensor location: ", tensor.Location().ToString()); + } + + return LoadWebAssemblyExternalData(env, data_file_path, data_offset, data_length, load_type, tensor.MutableDataRaw()); +} + +} // namespace webgpu +} // namespace onnxruntime + +#endif diff --git a/onnxruntime/core/providers/webgpu/external_data_loader.h b/onnxruntime/core/providers/webgpu/external_data_loader.h new file mode 100644 index 0000000000000..7ced4e930bf7a --- /dev/null +++ b/onnxruntime/core/providers/webgpu/external_data_loader.h @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#if defined(__wasm__) + +#include "core/framework/external_data_loader.h" + +namespace onnxruntime { +namespace webgpu { + +class ExternalDataLoader : public IExternalDataLoader { + public: + ExternalDataLoader() {}; + ~ExternalDataLoader() {}; + + bool CanLoad(const OrtMemoryInfo& target_memory_info) const override; + + common::Status LoadTensor(const Env& env, + const std::filesystem::path& data_file_path, + FileOffsetType data_offset, + SafeInt data_length, + Tensor& tensor) const override; +}; + +} // namespace webgpu +} // namespace onnxruntime + +#endif diff --git a/onnxruntime/core/providers/webgpu/generator/range.cc b/onnxruntime/core/providers/webgpu/generator/range.cc index a0b65f08a5b4e..99c5a1c1b5566 100644 --- a/onnxruntime/core/providers/webgpu/generator/range.cc +++ b/onnxruntime/core/providers/webgpu/generator/range.cc @@ -23,7 +23,7 @@ Status Range::ComputeInternal(ComputeContext& context) const { return Status::OK(); } - uint32_t output_size = gsl::narrow(n); + uint32_t output_size = onnxruntime::narrow(n); RangeProgram program{}; #if defined(__GNUC__) #pragma GCC diagnostic push diff --git a/onnxruntime/core/providers/webgpu/math/binary_elementwise_ops.cc b/onnxruntime/core/providers/webgpu/math/binary_elementwise_ops.cc index 75866513e2c7d..6891b8159b090 100644 --- a/onnxruntime/core/providers/webgpu/math/binary_elementwise_ops.cc +++ b/onnxruntime/core/providers/webgpu/math/binary_elementwise_ops.cc @@ -4,15 +4,18 @@ #include "core/providers/common.h" #include "core/providers/webgpu/math/binary_elementwise_ops.h" #include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/string_macros.h" #include "core/providers/webgpu/webgpu_supported_types.h" namespace onnxruntime { namespace webgpu { Status BinaryElementwiseProgram::GenerateShaderCode(ShaderHelper& shader) const { - const auto& a = shader.AddInput("input_a", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias); - const auto& b = shader.AddInput("input_b", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias); + const auto& a = shader.AddInput("input_a", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias); + const auto& b = shader.AddInput("input_b", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias); const auto& c = shader.AddOutput("output", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias); + shader.AdditionalImplementation() << additional_impl_; + shader.MainFunctionBody() << shader.GuardAgainstOutOfBoundsWorkgroupSizes("uniforms.vec_size"); // check whether can use element-wise mode. @@ -141,9 +144,16 @@ Status BinaryElementwise::ComputeInternal(ComputeContext& context) const { } } - uint32_t vec_size = gsl::narrow((size + 3) / 4); + uint32_t vec_size = onnxruntime::narrow((size + 3) / 4); + + std::string additional_impl; + if (get_additional_impl_) { + additional_impl = get_additional_impl_(lhs_tensor->GetElementType(), rhs_tensor->GetElementType()); + } + BinaryElementwiseProgram program{kernel_name_, expression_, + additional_impl, is_broadcast, is_lhs_scalar, is_rhs_scalar, @@ -190,9 +200,9 @@ Status BinaryElementwise::ComputeInternal(ComputeContext& context) const { // Mode Vectorize broadcast // cache hint: "V{a_rank};{b_rank};{output_rank}" program - .AddIndices(reshaped_output_shape) - .AddIndices(reshaped_lhs_shape) - .AddIndices(reshaped_rhs_shape) + .AddIndices(std::move(reshaped_output_shape)) + .AddIndices(std::move(reshaped_lhs_shape)) + .AddIndices(std::move(reshaped_rhs_shape)) .CacheHint("V"); } else { // Mode Broadcast @@ -273,7 +283,28 @@ WEBGPU_BINARY_VERSIONED_KERNEL(Sub, 7, 12, Sub, WebGpuSupportedNumberTypes()) WEBGPU_BINARY_VERSIONED_KERNEL(Sub, 13, 13, Sub, WebGpuSupportedNumberTypes()) WEBGPU_BINARY_KERNEL(Sub, 14, Sub, WebGpuSupportedNumberTypes()) -WEBGPU_BINARY_IMPL(Pow, "output_value_t(pow(vec4(a), vec4(b)))") +std::string GetPowImpl(int lhs_element_type, int /* rhs_element_type */) { + SS(s, 1024); + std::string round_str; + if (lhs_element_type == ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32) { + round_str = "round"; + } + + s << "fn pow_custom(a : input_a_element_t, b : f32) -> input_a_element_t {\n" + " if (b == 0.0) {\n" + " return input_a_element_t(1.0);\n" + " } else if (a < input_a_element_t(0.0) && b != floor(b)) {\n" + " return input_a_element_t(pow(f32(a), b)); // NaN\n" + " }\n" + << " return select(sign(a), input_a_element_t(1.0), round(abs(b) % 2.0) != 1.0) * input_a_element_t(" << round_str << "(pow(f32(abs(a)), b)));\n" + << "}\n" + "fn pow_v(a : vec4, b : vec4) -> vec4 {\n" + " return vec4(pow_custom(a.x, f32(b.x)), pow_custom(a.y, f32(b.y)), pow_custom(a.z, f32(b.z)), pow_custom(a.w, f32(b.w)));\n" + "}\n"; + return SS_GET(s); +} + +WEBGPU_BINARY_IMPL(Pow, "pow_v(a, b)", GetPowImpl) WEBGPU_BINARY_VERSIONED_KERNEL(Pow, 7, 11, Pow, WebGpuSupportedNumberTypes()) WEBGPU_BINARY_VERSIONED_KERNEL_2(Pow, 12, 12, Pow, WebGpuSupportedNumberTypes(), WebGpuSupportedNumberTypes()) WEBGPU_BINARY_VERSIONED_KERNEL_2(Pow, 13, 14, Pow, WebGpuSupportedNumberTypes(), WebGpuSupportedNumberTypes()) diff --git a/onnxruntime/core/providers/webgpu/math/binary_elementwise_ops.h b/onnxruntime/core/providers/webgpu/math/binary_elementwise_ops.h index 84cbcdf3244d8..f80accfb934f8 100644 --- a/onnxruntime/core/providers/webgpu/math/binary_elementwise_ops.h +++ b/onnxruntime/core/providers/webgpu/math/binary_elementwise_ops.h @@ -14,11 +14,13 @@ class BinaryElementwiseProgram final : public Program public: BinaryElementwiseProgram(const std::string& kernel_name, const std::string& expression, + const std::string& additional_impl, const bool is_broadcast, const bool is_lhs_scalar, const bool is_rhs_scalar, const bool vectorize) : Program{kernel_name}, expression_{expression}, + additional_impl_{additional_impl}, is_broadcast_{is_broadcast}, is_lhs_scalar_{is_lhs_scalar}, is_rhs_scalar_{is_rhs_scalar}, @@ -29,7 +31,8 @@ class BinaryElementwiseProgram final : public Program WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"vec_size", ProgramUniformVariableDataType::Uint32}); private: - std::string expression_; + std::string_view expression_; + std::string_view additional_impl_; bool is_broadcast_; bool is_lhs_scalar_; bool is_rhs_scalar_; @@ -38,11 +41,15 @@ class BinaryElementwiseProgram final : public Program class BinaryElementwise : public WebGpuKernel { public: + using GetAdditionalImplementationFunction = std::string (*)(int lhs_element_type, int rhs_element_type); + BinaryElementwise(const OpKernelInfo& info, const std::string& kernel_name, - const std::string& expression) : WebGpuKernel{info}, - kernel_name_{kernel_name}, - expression_{expression} {} + const std::string& expression, + const GetAdditionalImplementationFunction get_additional_impl = nullptr) : WebGpuKernel{info}, + kernel_name_{kernel_name}, + expression_{expression}, + get_additional_impl_{get_additional_impl} {} protected: Status ComputeInternal(ComputeContext& context) const final; @@ -50,6 +57,7 @@ class BinaryElementwise : public WebGpuKernel { private: std::string kernel_name_; std::string expression_; + const GetAdditionalImplementationFunction get_additional_impl_; }; } // namespace webgpu diff --git a/onnxruntime/core/providers/webgpu/math/cum_sum.cc b/onnxruntime/core/providers/webgpu/math/cum_sum.cc new file mode 100644 index 0000000000000..bc4cd70a238fc --- /dev/null +++ b/onnxruntime/core/providers/webgpu/math/cum_sum.cc @@ -0,0 +1,98 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/webgpu/math/cum_sum.h" +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/webgpu_supported_types.h" + +namespace onnxruntime { +namespace webgpu { + +ONNX_OPERATOR_VERSIONED_KERNEL_EX( + CumSum, + kOnnxDomain, + 11, 13, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T", WebGpuSupportedFloatTypes()) + .TypeConstraint("T2", {DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType()}) + .InputMemoryType(OrtMemTypeCPU, 1), + CumSum); + +ONNX_OPERATOR_KERNEL_EX( + CumSum, + kOnnxDomain, + 14, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T", WebGpuSupportedFloatTypes()) + .TypeConstraint("T2", {DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType()}) + .InputMemoryType(OrtMemTypeCPU, 1), + CumSum); + +Status CumSumProgram::GenerateShaderCode(ShaderHelper& shader) const { + const ShaderVariableHelper& input = shader.AddInput("input", ShaderUsage::UseUniform); + const ShaderVariableHelper& output = shader.AddOutput("output", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias); + + shader.MainFunctionBody() << shader.GuardAgainstOutOfBoundsWorkgroupSizes("uniforms.output_size") + << "var input_indices = " << input.OffsetToIndices("global_idx") << ";\n" + << "var sum : output_value_t = 0;\n" + << "var first : i32 = 0;\n" + << "if (uniforms.reverse == 1) {\n" + << " first = i32(" + input.IndicesGet("input_indices", "uniforms.axis") + ");\n" + << " if (uniforms.exclusive == 1) { first += 1; }\n" + << "}\n\n" + << "var last : i32 = 0;\n" + << "if (uniforms.reverse == 1) {\n" + << " last = i32(" << GetElementAt("uniforms.input_shape", "uniforms.axis", input.Rank()) << ");\n" + << "} else {\n" + << " last = i32(" + input.IndicesGet("input_indices", "uniforms.axis") + ");\n" + << " if (uniforms.exclusive == 0) { last += 1; }\n" + << "}\n\n" + << "for (var i : i32 = first; i < last; i++) {\n" + << " " << input.IndicesSet("input_indices", "uniforms.axis", "u32(i)") << ";\n" + << " sum = sum + " << input.GetByIndices("input_indices") << ";\n" + << "}\n" + << output.SetByOffset("global_idx", "sum"); + + return Status::OK(); +} + +Status CumSum::ComputeInternal(ComputeContext& context) const { + const auto* input_tensor = context.Input(0); + const TensorShape& input_shape = input_tensor->Shape(); + int64_t input_rank = input_shape.NumDimensions(); + + const auto* axis_tensor = context.Input(1); + const auto* axis_data = axis_tensor->Data(); + int64_t axis = static_cast(axis_data[0]); + + ORT_ENFORCE(-input_rank <= axis && axis < input_rank, "Axes attribute must be within range -input_rank <= axis < input_rank."); + // Handle negative axis + if (axis < 0) { + axis += input_rank; + } + + auto* output_tensor = context.Output(0, input_shape); + int64_t output_size = output_tensor->Shape().Size(); + + if (output_size == 0) { + return Status::OK(); + } + + CumSumProgram program{}; + program + .AddInput({input_tensor}) + .AddOutput({output_tensor, ProgramTensorMetadataDependency::TypeAndRank}) + .SetDispatchGroupSize((output_size + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE) + .AddUniformVariables({{static_cast(output_size)}, + {static_cast(axis)}, + {static_cast(exclusive_)}, + {static_cast(reverse_)}}); + return context.RunProgram(program); +} + +} // namespace webgpu +} // namespace onnxruntime \ No newline at end of file diff --git a/onnxruntime/core/providers/webgpu/math/cum_sum.h b/onnxruntime/core/providers/webgpu/math/cum_sum.h new file mode 100644 index 0000000000000..6a66ee0ed7b04 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/math/cum_sum.h @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/webgpu/webgpu_kernel.h" +#include "core/providers/webgpu/program.h" + +namespace onnxruntime { +namespace webgpu { + +class CumSumProgram final : public Program { + public: + CumSumProgram() : Program{"CumSum"} {} + + Status GenerateShaderCode(ShaderHelper& sh) const override; + + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"output_size", ProgramUniformVariableDataType::Uint32}, + {"axis", ProgramUniformVariableDataType::Uint32}, + {"exclusive", ProgramUniformVariableDataType::Uint32}, + {"reverse", ProgramUniformVariableDataType::Uint32}); +}; + +class CumSum final : public WebGpuKernel { + public: + CumSum(const OpKernelInfo& info) : WebGpuKernel(info) { + exclusive_ = info.GetAttrOrDefault("exclusive", 0); + reverse_ = info.GetAttrOrDefault("reverse", 0); + } + + Status ComputeInternal(ComputeContext& context) const override; + + private: + int64_t exclusive_; + int64_t reverse_; +}; + +} // namespace webgpu +} // namespace onnxruntime \ No newline at end of file diff --git a/onnxruntime/core/providers/webgpu/math/gemm.cc b/onnxruntime/core/providers/webgpu/math/gemm.cc new file mode 100644 index 0000000000000..4057b63f0c65d --- /dev/null +++ b/onnxruntime/core/providers/webgpu/math/gemm.cc @@ -0,0 +1,236 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/webgpu/math/gemm.h" + +#include + +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/webgpu_supported_types.h" + +namespace onnxruntime { +namespace webgpu { + +#define WEBGPU_GEMM_VERSIONED_KERNEL(start, end) \ + ONNX_OPERATOR_VERSIONED_KERNEL_EX( \ + Gemm, \ + kOnnxDomain, \ + start, \ + end, \ + kWebGpuExecutionProvider, \ + (*KernelDefBuilder::Create()) \ + .TypeConstraint("T", WebGpuSupportedNumberTypes()), \ + Gemm); + +#define WEBGPU_GEMM_KERNEL(version) \ + ONNX_OPERATOR_KERNEL_EX( \ + Gemm, \ + kOnnxDomain, \ + version, \ + kWebGpuExecutionProvider, \ + (*KernelDefBuilder::Create()) \ + .TypeConstraint("T", WebGpuSupportedNumberTypes()), \ + Gemm); + +WEBGPU_GEMM_VERSIONED_KERNEL(7, 8) +WEBGPU_GEMM_VERSIONED_KERNEL(9, 10) +WEBGPU_GEMM_VERSIONED_KERNEL(11, 12) +WEBGPU_GEMM_KERNEL(13) + +Status GemmProgram::GenerateShaderCode(ShaderHelper& shader) const { + const uint32_t TILE_SIZE = 16; + + // Add shared memory arrays + shader.AdditionalImplementation() << "var tile_a: array, " << TILE_SIZE << ">;\n" + << "var tile_b: array, " << TILE_SIZE << ">;\n\n"; + + const ShaderVariableHelper& output = shader.AddOutput("output", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias); + + shader.MainFunctionBody() << " var value = output_value_t(0);\n\n" + << " let tile_col_start = (workgroup_idx % uniforms.num_tile_n) * " << TILE_SIZE << "u;\n" + << " let tile_row_start = (workgroup_idx / uniforms.num_tile_n) * " << TILE_SIZE << "u;\n"; + + // When A or B is empty, we don't bind A and B. Because WebGPU doesn't support binding a zero-sized buffer. + if (need_handle_matmul_) { + const ShaderVariableHelper& A = shader.AddInput("A", ShaderUsage::UseUniform); + const ShaderVariableHelper& B = shader.AddInput("B", ShaderUsage::UseUniform); + + shader.MainFunctionBody() + << " let num_tiles = (uniforms.K - 1u) / " << TILE_SIZE << "u + 1u;\n" + << " var k_start = 0u;\n" + << " for (var t = 0u; t < num_tiles; t = t + 1u) {\n"; + + // Fill workgroup shared memory + if (transA_ && transB_) { + shader.MainFunctionBody() << " var col = tile_row_start + local_id.x;\n" + << " var row = k_start + local_id.y;\n" + << " if (col < uniforms.M && row < uniforms.K) {\n" + << " tile_a[local_id.y][local_id.x] = " << A.GetByOffset("row * uniforms.M + col") << ";\n" + << " } else {\n" + << " tile_a[local_id.y][local_id.x] = output_value_t(0);\n" + << " }\n\n" + << " col = k_start + local_id.x;\n" + << " row = tile_col_start + local_id.y;\n" + << " if (col < uniforms.K && row < uniforms.N) {\n" + << " tile_b[local_id.y][local_id.x] = " << B.GetByOffset("row * uniforms.K + col") << ";\n" + << " } else {\n" + << " tile_b[local_id.y][local_id.x] = output_value_t(0);\n" + << " }\n"; + } else if (transA_ && !transB_) { + shader.MainFunctionBody() << " var col = tile_row_start + local_id.x;\n" + << " var row = k_start + local_id.y;\n" + << " if (col < uniforms.M && row < uniforms.K) {\n" + << " tile_a[local_id.y][local_id.x] = " << A.GetByOffset("row * uniforms.M + col") << ";\n" + << " } else {\n" + << " tile_a[local_id.y][local_id.x] = output_value_t(0);\n" + << " }\n\n" + << " col = tile_col_start + local_id.x;\n" + << " row = k_start + local_id.y;\n" + << " if (col < uniforms.N && row < uniforms.K) {\n" + << " tile_b[local_id.y][local_id.x] = " << B.GetByOffset("row * uniforms.N + col") << ";\n" + << " } else {\n" + << " tile_b[local_id.y][local_id.x] = output_value_t(0);\n" + << " }\n"; + } else if (!transA_ && transB_) { + shader.MainFunctionBody() << " var col = k_start + local_id.x;\n" + << " var row = tile_row_start + local_id.y;\n" + << " if (col < uniforms.K && row < uniforms.M) {\n" + << " tile_a[local_id.y][local_id.x] = " << A.GetByOffset("row * uniforms.K + col") << ";\n" + << " } else {\n" + << " tile_a[local_id.y][local_id.x] = output_value_t(0);\n" + << " }\n\n" + << " col = k_start + local_id.x;\n" + << " row = tile_col_start + local_id.y;\n" + << " if (col < uniforms.K && row < uniforms.N) {\n" + << " tile_b[local_id.y][local_id.x] = " << B.GetByOffset("row * uniforms.K + col") << ";\n" + << " } else {\n" + << " tile_b[local_id.y][local_id.x] = output_value_t(0);\n" + << " }\n"; + } else { + shader.MainFunctionBody() << " var col = k_start + local_id.x;\n" + << " var row = tile_row_start + local_id.y;\n" + << " if (col < uniforms.K && row < uniforms.M) {\n" + << " tile_a[local_id.y][local_id.x] = " << A.GetByOffset("row * uniforms.K + col") << ";\n" + << " } else {\n" + << " tile_a[local_id.y][local_id.x] = output_value_t(0);\n" + << " }\n\n" + << " col = tile_col_start + local_id.x;\n" + << " row = k_start + local_id.y;\n" + << " if (col < uniforms.N && row < uniforms.K) {\n" + << " tile_b[local_id.y][local_id.x] = " << B.GetByOffset("row * uniforms.N + col") << ";\n" + << " } else {\n" + << " tile_b[local_id.y][local_id.x] = output_value_t(0);\n" + << " }\n"; + } + + shader.MainFunctionBody() << " k_start = k_start + " << TILE_SIZE << "u;\n" + << " workgroupBarrier();\n\n" + << " for (var k = 0u; k < " << TILE_SIZE << "u; k = k + 1u) {\n"; + + if (transA_ && transB_) { + shader.MainFunctionBody() << " value = value + tile_a[k][local_id.y] * tile_b[local_id.x][k];\n"; + } else if (transA_ && !transB_) { + shader.MainFunctionBody() << " value = value + tile_a[k][local_id.y] * tile_b[k][local_id.x];\n"; + } else if (!transA_ && transB_) { + shader.MainFunctionBody() << " value = value + tile_a[local_id.y][k] * tile_b[local_id.x][k];\n"; + } else { + shader.MainFunctionBody() << " value = value + tile_a[local_id.y][k] * tile_b[k][local_id.x];\n"; + } + + shader.MainFunctionBody() << " }\n" + << " workgroupBarrier();\n" + << " }\n\n"; + } + + // Calculate Alpha + if (alpha_) { + shader.MainFunctionBody() << " value = value * output_value_t(uniforms.alpha);\n"; + } + + shader.MainFunctionBody() << " let m = tile_row_start + local_id.y;\n" + << " let n = tile_col_start + local_id.x;\n"; + + // Calculate Bias + if (need_handle_bias_) { + const ShaderVariableHelper& C = shader.AddInput("C", ShaderUsage::UseUniform); + shader.MainFunctionBody() << " value = value + output_value_t(uniforms.beta) * " + << C.GetByOffset(C.BroadcastedIndicesToOffset("vec2(m, n)", output)) << ";\n"; + } + + // Write output + shader.MainFunctionBody() << " if (m < uniforms.M && n < uniforms.N) {\n" + << " " << output.SetByOffset("m * uniforms.N + n", "value") << "\n" + << " }\n"; + + return Status::OK(); +} + +Status Gemm::ComputeInternal(ComputeContext& context) const { + const auto* A = context.Input(0); + const auto* B = context.Input(1); + const auto* C = context.Input(2); + + if (A == nullptr || B == nullptr) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Gemm requires input tensors A and B."); + } + + const auto& A_shape = A->Shape(); + const auto& B_shape = B->Shape(); + + if (A_shape.NumDimensions() != 2 || B_shape.NumDimensions() != 2) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Input tensors A and B must be 2 dimensional."); + } + + uint32_t M = onnxruntime::narrow(transA_ ? A_shape[1] : A_shape[0]); + uint32_t K = onnxruntime::narrow(transA_ ? A_shape[0] : A_shape[1]); + uint32_t N = onnxruntime::narrow(transB_ ? B_shape[0] : B_shape[1]); + + if ((transA_ ? A_shape[0] : A_shape[1]) != (transB_ ? B_shape[1] : B_shape[0])) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Inner dimensions of A and B must match."); + } + + std::vector output_dims{M, N}; + auto* Y = context.Output(0, output_dims); + int64_t output_size = Y->Shape().Size(); + + if (output_size == 0) { + return Status::OK(); + } + + // WebGPU doesn't support binding a zero-sized buffer, so we need to check if A or B is empty. + bool need_handle_matmul = A_shape.Size() > 0 && B_shape.Size() > 0; + bool need_handle_bias = C && beta_; + + GemmProgram program{transA_, transB_, alpha_, need_handle_bias, need_handle_matmul}; + + if (need_handle_matmul) { + program.AddInputs({{A, ProgramTensorMetadataDependency::Type}, + {B, ProgramTensorMetadataDependency::Type}}); + } + + if (need_handle_bias) { + program.AddInput({C, ProgramTensorMetadataDependency::Rank}); + } + + const uint32_t TILE_SIZE = 16; + const uint32_t num_tile_n = (N + TILE_SIZE - 1) / TILE_SIZE; + const uint32_t num_tile_m = (M + TILE_SIZE - 1) / TILE_SIZE; + + program.CacheHint(alpha_, transA_, transB_) + .AddOutputs({{Y, ProgramTensorMetadataDependency::Type}}) + .SetDispatchGroupSize(num_tile_n * num_tile_m) + .SetWorkgroupSize(TILE_SIZE, TILE_SIZE) + .AddUniformVariables({ + {static_cast(num_tile_n)}, // num_tile_n + {static_cast(M)}, // M + {static_cast(N)}, // N + {static_cast(K)}, // K + {alpha_}, // alpha + {beta_} // beta + }); + + return context.RunProgram(program); +} + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/math/gemm.h b/onnxruntime/core/providers/webgpu/math/gemm.h new file mode 100644 index 0000000000000..7fee1091de5f8 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/math/gemm.h @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/webgpu/webgpu_kernel.h" +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/program.h" + +namespace onnxruntime { +namespace webgpu { + +class GemmProgram final : public Program { + public: + GemmProgram(bool transA, bool transB, float alpha, bool need_handle_bias, bool need_handle_matmul) + : Program{"Gemm"}, + transA_{transA}, + transB_{transB}, + alpha_{alpha}, + need_handle_bias_{need_handle_bias}, + need_handle_matmul_{need_handle_matmul} {} + + Status GenerateShaderCode(ShaderHelper& sh) const override; + + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES( + {"num_tile_n", ProgramUniformVariableDataType::Uint32}, + {"M", ProgramUniformVariableDataType::Uint32}, + {"N", ProgramUniformVariableDataType::Uint32}, + {"K", ProgramUniformVariableDataType::Uint32}, + {"alpha", ProgramUniformVariableDataType::Float32}, + {"beta", ProgramUniformVariableDataType::Float32}); + + private: + bool transA_; + bool transB_; + float alpha_; + bool need_handle_bias_; + bool need_handle_matmul_; +}; + +class Gemm final : public WebGpuKernel { + public: + Gemm(const OpKernelInfo& info) : WebGpuKernel(info) { + int64_t transA_temp; + info.GetAttrOrDefault("transA", &transA_temp, static_cast(0)); + transA_ = transA_temp != 0; + + int64_t transB_temp; + info.GetAttrOrDefault("transB", &transB_temp, static_cast(0)); + transB_ = transB_temp != 0; + + info.GetAttrOrDefault("alpha", &alpha_, 1.0f); + info.GetAttrOrDefault("beta", &beta_, 1.0f); + } + + Status ComputeInternal(ComputeContext& context) const override; + + private: + bool transA_; + bool transB_; + float alpha_; + float beta_; +}; + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/math/matmul.cc b/onnxruntime/core/providers/webgpu/math/matmul.cc new file mode 100644 index 0000000000000..cdd3909874e7f --- /dev/null +++ b/onnxruntime/core/providers/webgpu/math/matmul.cc @@ -0,0 +1,254 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/webgpu/math/matmul.h" +#include "core/common/inlined_containers.h" +#include "core/providers/cpu/tensor/utils.h" +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/webgpu_supported_types.h" +#include "core/providers/webgpu/nn/fuse_utils.h" +#include "core/providers/webgpu/data_transfer.h" + +namespace onnxruntime { +namespace webgpu { + +ONNX_OPERATOR_VERSIONED_KERNEL_EX( + MatMul, + kOnnxDomain, + 1, 12, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T", WebGpuSupportedFloatTypes()), + MatMul); + +ONNX_OPERATOR_KERNEL_EX( + MatMul, + kOnnxDomain, + 13, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T", WebGpuSupportedFloatTypes()), + MatMul); + +static std::string CalcResult(int64_t components, int64_t a_components, int64_t output_number) { + std::ostringstream oss; + oss << "var a_data: a_value_t;\n"; + for (int i = 0; i < a_components; ++i) { + oss << "let b_data" << i << " = b[(b_offset + (k + " << i << ") * uniforms.N + col) / " << components << "];\n"; + } + for (int i = 0; i < output_number; ++i) { + oss << "a_data = a[(a_offset + (row + " << i << ") * uniforms.K + k) / " << a_components << "];\n"; + + for (int j = 0; j < a_components; j++) { + oss << "values[" << i << "] = fma(b_value_t(a_data" << (a_components == 1 ? "" : "[" + std::to_string(j) + "]") << "), b_data" << j << ", values[" << i << "]);\n"; + } + } + return oss.str(); +} + +Status MatMulNaiveProgram::GenerateShaderCode(ShaderHelper& shader) const { + const auto& a = shader.AddInput("a", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias | + ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias); + const auto& b = shader.AddInput("b", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias | + ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias); + + std::string process_bias; + if (has_bias_) { + shader.AddInput("bias", ShaderUsage::UseUniform); + process_bias = is_channels_last_ ? "value += output_value_t(bias[col])" : "value += output_value_t(bias[row + i]);"; + } + + std::string apply_activation = GetActivationSnippet(activation_, "output_value_t", "output_element_t"); + const auto& output = shader.AddOutput("output", ShaderUsage::UseUniform | + ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias); + const auto& batch_dims = shader.AddIndices("batch_dims"); + + int a_components = a.NumComponents(); + int components = b.NumComponents(); // components of N + + shader.MainFunctionBody() << shader.GuardAgainstOutOfBoundsWorkgroupSizes("uniforms.output_size") + << "let col = (global_idx % (uniforms.N / " << components << ")) * " << components << ";\n" + << "var index1 = global_idx / (uniforms.N / " << components << ");\n" + << "let stride1 = uniforms.M / " << output_number_ << ";\n" + << "let row = (index1 % stride1) * " << output_number_ << ";\n" + << "let batch = index1 / stride1;\n"; + if (output_rank_ != 2) { + shader.MainFunctionBody() << "let batch_indices = " << batch_dims.OffsetToIndices("batch") << ";\n"; + } + shader.MainFunctionBody() << "var a_indices: a_indices_t;\n" + << ConvertOutputBatchIndicesToInputBatchIndices("a", a, a.Rank() - 2, batch_dims.Rank(), "batch_indices") + << a.IndicesSet("a_indices", a.Rank() - 2, 0) << "\n" + << a.IndicesSet("a_indices", a.Rank() - 1, 0) << "\n" + << "let a_offset = " << a.IndicesToOffset("a_indices") << "*" << a_components << ";\n" + << "var b_indices: b_indices_t;\n" + << ConvertOutputBatchIndicesToInputBatchIndices("b", b, b.Rank() - 2, batch_dims.Rank(), "batch_indices") + << b.IndicesSet("b_indices", b.Rank() - 2, 0) << "\n" + << b.IndicesSet("b_indices", b.Rank() - 1, 0) << "\n" + << "let b_offset = " << b.IndicesToOffset("b_indices") << " * " << components << ";\n" + << "var values: array;\n" + << "for (var k: u32 = 0u; k < uniforms.K; k = k + " << a_components << ") {\n" + << CalcResult(components, a_components, output_number_) << "\n" + << "}\n" + << "for (var i = 0u; i < " << output_number_ << "u; i++) {\n" + << " var value = values[i];\n" + << process_bias << "\n" + << apply_activation << "\n" + << " let cur_indices = output_indices_t(batch, row + i, col/ " << components << ");\n" + << " let offset = " << output.IndicesToOffset("cur_indices") << ";\n" + << output.SetByOffset("offset", "value") + << "}\n"; + + return Status::OK(); +} + +Status MatMul::ComputeInternal(ComputeContext& context) const { + // calculate output shape + MatMulComputeHelper helper; + const auto* a = context.Input(0); + const auto* b = context.Input(1); + + ORT_RETURN_IF_ERROR(helper.Compute(a->Shape(), b->Shape())); + auto* output_tensor = context.Output(0, helper.OutputShape()); + bool has_bias = context.InputCount() > 2; + + if (helper.N() < 8 && helper.K() < 8) { // call MatMulNaiveProgram + + const uint32_t m = narrow(helper.M()); // left matrix first dimension + const uint32_t n = narrow(helper.N()); // right matrix second dimension + const uint32_t k = narrow(helper.K()); // right matrix first dimension + + const auto components = GetMaxComponents(n); + const auto a_components = GetMaxComponents(k); + + const auto output_number = GetMaxComponents(m); + uint32_t output_size = narrow(helper.OutputShape().Size() / components / output_number); + + const size_t output_rank = helper.OutputShape().NumDimensions(); + TensorShape outer_dims = output_rank > 2 ? helper.OutputShape().Slice(0, output_rank - 2) : TensorShape({}); + const int64_t batch_size = outer_dims.Size(); + + const int64_t a_rows = a->Shape().NumDimensions() > 1 ? a->Shape()[a->Shape().NumDimensions() - 2] : 1; + TensorShape output_shape_shader({batch_size, a_rows, helper.N() / components}); + + MatMulNaiveProgram program{Activation(), output_rank, output_number, has_bias}; + + program + .CacheHint(std::to_string(components), std::to_string(a_components), std::to_string(output_number)) + .AddInputs({{a, ProgramTensorMetadataDependency::TypeAndRank, a_components}, + {b, ProgramTensorMetadataDependency::TypeAndRank, components}}); + + if (has_bias) { + const auto* bias = context.Input(2); + program.AddInput({bias, ProgramTensorMetadataDependency::Rank, 1}); + } + program + .AddOutputs({{output_tensor, ProgramTensorMetadataDependency::None, output_shape_shader, components}}) + .SetDispatchGroupSize((output_size + 63) / 64) // Integer ceiling division + .AddIndices(outer_dims) + .AddUniformVariables({{output_size}, {m}, {n}, {k}}); + + return context.RunProgram(program); + } + + std::vector inputs(has_bias ? 3 : 2); + inputs[0] = a; + inputs[1] = b; + if (has_bias) { + const auto* bias = context.Input(2); + inputs.push_back(bias); + } + auto program = CreateMatMulProgram(Activation(), inputs, output_tensor, false); + + return context.RunProgram(program); +} + +MatMulProgram CreateMatMulProgram(const Activation& activation, std::vector& inputs, Tensor* output_tensor, bool is_channels_last, + const TensorShape& input_a_reshape, + const TensorShape& input_b_reshape) { + const auto* a = inputs[0]; + const auto* b = inputs[1]; + bool has_bias = inputs.size() > 2; + TensorShape a_shape = input_a_reshape.NumDimensions() > 0 ? input_a_reshape : a->Shape(); + TensorShape b_shape = input_b_reshape.NumDimensions() > 0 ? input_b_reshape : b->Shape(); + + MatMulComputeHelper helper; + ORT_THROW_IF_ERROR(helper.Compute(a_shape, b_shape)); + int64_t batchA = a_shape.SizeToDimension(a_shape.NumDimensions() - 2); + int64_t batchB = b_shape.SizeToDimension(b_shape.NumDimensions() - 2); + + TensorShape output_shape = helper.OutputShape(); + + const int64_t dim_output_outer = output_shape[output_shape.NumDimensions() - 2]; + // check if A is batch of vector (bach is not 1, M is 1) and B is a matrix (batch is 1) + if (batchA != 1 && dim_output_outer == 1 && batchB == 1) { + // optimization for batched vector matrix multiplication + // dimensions of A: [1,`batchA`,K] + TensorShapeVector dims_a = {1, batchA, helper.K()}; + // dimensions of B: [1,K,N] + TensorShapeVector dims_b = {1, helper.K(), helper.N()}; + + a_shape = TensorShape(dims_a); + b_shape = TensorShape(dims_b); + output_shape = {1, batchA, helper.N()}; + } + + // helpful dimension variables + TensorShape outer_dims_a = a_shape.NumDimensions() > 2 + ? a_shape.Slice(0, a_shape.NumDimensions() - 2) + : TensorShape({}); + + TensorShape outer_dims_b = b_shape.NumDimensions() > 2 + ? b_shape.Slice(0, b_shape.NumDimensions() - 2) + : TensorShape({}); + + TensorShape outer_dims = output_shape.NumDimensions() > 2 + ? output_shape.Slice(0, output_shape.NumDimensions() - 2) + : TensorShape({}); + + const int64_t batch_size = outer_dims.Size(); + + // Get dimensions for matrix multiplication from TensorShape + const uint32_t dim_a_outer = narrow(a_shape[a_shape.NumDimensions() - 2]); // left matrix second dimension + const uint32_t dim_inner = narrow(a_shape[a_shape.NumDimensions() - 1]); // left matrix first dimension + const uint32_t dim_b_outer = narrow(b_shape[b_shape.NumDimensions() - 1]); // right matrix first dimension + + const bool is_vec4 = dim_inner % 4 == 0 && dim_b_outer % 4 == 0; + + InlinedVector elements_per_thread = dim_a_outer <= 8 + ? InlinedVector({4, 1, 1}) + : InlinedVector({4, 4, 1}); + + const uint32_t dispatch_x = narrow((dim_b_outer + MatMul::MATMUL_PACKED_WORKGROUP_SIZE_X * elements_per_thread[0] - 1) / + (MatMul::MATMUL_PACKED_WORKGROUP_SIZE_X * elements_per_thread[0])); + const uint32_t dispatch_y = narrow((dim_a_outer + MatMul::MATMUL_PACKED_WORKGROUP_SIZE_Y * elements_per_thread[1] - 1) / + (MatMul::MATMUL_PACKED_WORKGROUP_SIZE_Y * elements_per_thread[1])); + const uint32_t dispatch_z = narrow((static_cast(batch_size) + MatMul::MATMUL_PACKED_WORKGROUP_SIZE_Z * elements_per_thread[2] - 1) / + (MatMul::MATMUL_PACKED_WORKGROUP_SIZE_Z * elements_per_thread[2])); + + const int components = is_vec4 ? 4 : 1; + const TensorShape a_shape_temp = CreateMatMulIntermediateShape(outer_dims_a, dim_a_outer, dim_inner, components); + const TensorShape b_shape_temp = CreateMatMulIntermediateShape(outer_dims_b, dim_inner, dim_b_outer, components); + const TensorShape output_shape_temp = TensorShape({batch_size, dim_a_outer, dim_b_outer / components}); + + MatMulProgram program{activation, has_bias, is_vec4, elements_per_thread, is_channels_last}; + program + .CacheHint(activation.ToString(), absl::StrJoin(elements_per_thread, "-"), std::to_string(is_vec4)) + .AddInputs({{a, ProgramTensorMetadataDependency::TypeAndRank, a_shape_temp, components}, + {b, ProgramTensorMetadataDependency::TypeAndRank, b_shape_temp, components}}) + .AddOutputs({{output_tensor, ProgramTensorMetadataDependency::Rank, output_shape_temp, components}}) + .AddUniformVariables({{dim_a_outer}, {dim_b_outer}, {dim_inner}}) + .AddIndices(outer_dims) + .SetDispatchGroupSize(dispatch_x, dispatch_y, dispatch_z) + .SetWorkgroupSize(MatMul::MATMUL_PACKED_WORKGROUP_SIZE_X, MatMul::MATMUL_PACKED_WORKGROUP_SIZE_Y, MatMul::MATMUL_PACKED_WORKGROUP_SIZE_Z); + + if (has_bias) { + auto bias_components = is_channels_last ? components : 1; + const auto* bias = inputs[2]; + TensorShape reduced_bias_shape = ReduceShapeByComponents(bias->Shape(), bias_components); + program.AddInput({bias, ProgramTensorMetadataDependency::Rank, reduced_bias_shape, bias_components}); + } + return program; +} + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/math/matmul.h b/onnxruntime/core/providers/webgpu/math/matmul.h new file mode 100644 index 0000000000000..91216d8e25eec --- /dev/null +++ b/onnxruntime/core/providers/webgpu/math/matmul.h @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/webgpu/webgpu_kernel.h" +#include "core/providers/webgpu/program.h" +#include "core/providers/cpu/math/matmul_helper.h" +#include "core/providers/webgpu/math/matmul_utils.h" +#include "core/providers/webgpu/math/matmul_packed.h" +#include "core/providers/webgpu/webgpu_utils.h" +#include "core/providers/webgpu/nn/fuse_utils.h" + +namespace onnxruntime { +namespace webgpu { + +MatMulProgram CreateMatMulProgram(const Activation& activation, std::vector& inputs, Tensor* output, bool is_channels_last, + const TensorShape& input_a_reshape = TensorShape(), + const TensorShape& input_b_reshape = TensorShape()); + +class MatMul final : public WebGpuKernel { + public: + MatMul(const OpKernelInfo& info) : WebGpuKernel{info} {} + + Status ComputeInternal(ComputeContext& context) const override; + constexpr static uint32_t MATMUL_PACKED_WORKGROUP_SIZE_X = 8; + constexpr static uint32_t MATMUL_PACKED_WORKGROUP_SIZE_Y = 8; + constexpr static uint32_t MATMUL_PACKED_WORKGROUP_SIZE_Z = 1; +}; + +class MatMulNaiveProgram final : public Program { + public: + MatMulNaiveProgram(const Activation& activation, const size_t output_rank, int64_t output_number, bool has_bias, bool is_channels_last = false) + : Program{"MatMulNaive"}, activation_(activation), output_rank_(output_rank), output_number_(output_number), has_bias_{has_bias}, is_channels_last_(is_channels_last) { + } + + Status GenerateShaderCode(ShaderHelper& sh) const override; + + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"output_size", ProgramUniformVariableDataType::Uint32}, + {"M", ProgramUniformVariableDataType::Uint32}, + {"N", ProgramUniformVariableDataType::Uint32}, + {"K", ProgramUniformVariableDataType::Uint32}); + + private: + const Activation& activation_; + const size_t output_rank_; + const int64_t output_number_; + const bool has_bias_; + const bool is_channels_last_; +}; + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/math/matmul_packed.cc b/onnxruntime/core/providers/webgpu/math/matmul_packed.cc new file mode 100644 index 0000000000000..36510eec0cd3b --- /dev/null +++ b/onnxruntime/core/providers/webgpu/math/matmul_packed.cc @@ -0,0 +1,384 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/webgpu/math/matmul_packed.h" +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/webgpu_supported_types.h" +#include "core/providers/webgpu/webgpu_utils.h" +#include +namespace onnxruntime { +namespace webgpu { + +void MatMulProgram::MatMulReadWriteFnSource(ShaderHelper& shader, + const ShaderVariableHelper& a, + const ShaderVariableHelper& b, + const ShaderVariableHelper& output, + const ShaderIndicesHelper& batch_dims, + std::string activation_snippet) const { + int components = is_vec4_ ? 4 : 1; + const std::string data_type = "a_element_t"; + const std::string type_string = MakeScalarOrVectorType(components, data_type); + + // Add the mm_readA function + shader.AdditionalImplementation() + << "fn mm_readA(batch: i32, row: i32, colIn: i32, batch_indices: batch_dims_indices_t) -> " << type_string << " {\n" + << " var value = " << type_string << "(0.0);\n" + << " let col = colIn * " << components << ";\n" + << " if(row < i32(uniforms.dim_a_outer) && col < i32(uniforms.dim_inner)) {\n" + << " var a_indices: a_indices_t;\n" + << ConvertOutputBatchIndicesToInputBatchIndices("a", a, a.Rank() - 2, batch_dims.Rank(), "batch_indices") + << a.IndicesSet("a_indices", a.Rank() - 2, "u32(row)") << "\n" + << a.IndicesSet("a_indices", a.Rank() - 1, "u32(colIn)") << "\n" + << " value = " << a.GetByIndices("a_indices") << ";\n" + << " }\n" + << " return value;\n" + << "}\n\n"; + + // Add the mm_readB function + shader.AdditionalImplementation() + << "fn mm_readB(batch: i32, row: i32, colIn: i32, batch_indices: batch_dims_indices_t) -> " << type_string << " {\n" + << " var value = " << type_string << "(0.0);\n" + << " let col = colIn * " << components << ";\n" + << " if(row < i32(uniforms.dim_inner) && col < i32(uniforms.dim_b_outer)) {\n" + << " var b_indices: b_indices_t;\n" + << ConvertOutputBatchIndicesToInputBatchIndices("b", b, b.Rank() - 2, batch_dims.Rank(), "batch_indices") + << b.IndicesSet("b_indices", b.Rank() - 2, "u32(row)") << "\n" + << b.IndicesSet("b_indices", b.Rank() - 1, "u32(colIn)") << "\n" + << " value = " << b.GetByIndices("b_indices") << ";\n" + << " }\n" + << " return value;\n" + << "}\n\n"; + + // Add the mm_write function + shader.AdditionalImplementation() + << "fn mm_write(batch: i32, row: i32, colIn: i32, valueIn: " << type_string << ") {\n" + << " let col = colIn * " << components << ";\n" + << " if (row < i32(uniforms.dim_a_outer) && col < i32(uniforms.dim_b_outer)) {\n" + << " var value = valueIn;\n" + << " let coords = vec3(batch, row, colIn);\n"; + + if (has_bias_) { + shader.AdditionalImplementation() << " value = value + " << (is_channels_last_ ? "bias[colIn]" : type_string + "(bias[row])") << ";\n"; + } + + shader.AdditionalImplementation() << " " << activation_snippet << "\n"; + + shader.AdditionalImplementation() + << output.SetByIndices("vec3(coords)", "value") << "\n" + << " }\n" + << "}\n\n"; +} + +Status MatMulProgram::MakeMatMulPackedVec4Source(ShaderHelper& shader, + const InlinedVector& elements_per_thread, + uint32_t workgroup_size_x, + uint32_t workgroup_size_y, + const std::string& data_type, + const ShaderIndicesHelper* batch_dims, + bool transpose_a, + uint32_t tile_inner, + bool split_k, + uint32_t splitted_dim_inner) { + ORT_UNUSED_PARAMETER(split_k); + ORT_UNUSED_PARAMETER(splitted_dim_inner); + std::string write_data_to_sub_a_vec4_snippet = + transpose_a ? std::string("mm_Asub[inputRow][inputCol] = mm_readA(batch, kStart + inputRow, globalRowStart / innerElementSize + inputCol") + (batch_dims ? ", batchIndices" : "") + ");\n" + : std::string("mm_Asub[inputRow][inputCol] = mm_readA(batch, globalRow + innerRow, kStart / innerElementSize + inputCol") + (batch_dims ? ", batchIndices" : "") + ");\n"; + // elements per thread + const auto elements_per_thread_x = elements_per_thread[0]; + const auto elements_per_thread_y = elements_per_thread[1]; + + const auto tile_a_outer = workgroup_size_y * elements_per_thread_y; + const auto tile_b_outer = workgroup_size_x * elements_per_thread_x; + const auto tile_a_width = transpose_a ? tile_a_outer : tile_inner; + const auto tile_a_height = transpose_a ? tile_inner : tile_a_outer; + const auto inner_elements_size = tile_a_width / workgroup_size_x; + const auto row_per_thread_b = tile_inner / workgroup_size_y; + + if (!((transpose_a && inner_elements_size == 4 && elements_per_thread[1] == 4) || + (!transpose_a && (inner_elements_size == 3 || inner_elements_size == 4))) && + tile_a_width % workgroup_size_x == 0 && + tile_inner % workgroup_size_y == 0 && + elements_per_thread_x == 4) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Invalid matrix multiplication configuration inner_elements_size: ", inner_elements_size, + " must be 3 or 4. tile_a_width: ", tile_a_width, " must be divisible by WorkgroupSizeX: ", + workgroup_size_x, ". tile_inner: ", tile_inner, " must be divisible by WorkgroupSizeY: ", + workgroup_size_y, ". elements_per_thread_x: ", elements_per_thread_x, " must be 4."); + } + + shader.AdditionalImplementation() + << "var mm_Asub: array, " << tile_a_width / inner_elements_size << ">, " << tile_a_height << ">;\n" + << "var mm_Bsub: array, " << tile_b_outer / elements_per_thread_x << ">, " << tile_inner << ">;\n" + << "const rowPerThread = " << elements_per_thread_y << ";\n" + << "const colPerThread = " << elements_per_thread_x << ";\n" + << "const innerElementSize = " << inner_elements_size << ";\n" + << "const tileInner = " << tile_inner << ";\n"; + + shader.MainFunctionBody() + << " let localRow = i32(local_id.y);\n" + << " let tileRow = localRow * rowPerThread;\n" + << " let tileCol = i32(local_id.x);\n" + << " let globalRow = i32(global_id.y) * rowPerThread;\n" + << " let globalCol = i32(global_id.x);\n" + << " let batch = i32(global_id.z);\n" + << (nullptr != batch_dims ? " let batchIndices = " + batch_dims->OffsetToIndices("u32(batch)") + ";\n" : "") + << " let globalRowStart = i32(workgroup_id.y) * " << tile_a_outer << ";\n" + << " let num_tiles = (uniforms.dim_inner - 1) / tileInner + 1;\n" + << " var kStart = 0;\n" + << " var acc: array, rowPerThread>;\n"; + + // Loop over shared dimension. + shader.MainFunctionBody() + << " let tileRowB = localRow * " << row_per_thread_b << ";\n" + << " for (var t = 0; t < i32(num_tiles); t = t + 1) {\n"; + + // Load one tile of A into local memory. + shader.MainFunctionBody() + << " for (var innerRow = 0; innerRow < rowPerThread; innerRow = innerRow + 1) {\n" + << " let inputRow = tileRow + innerRow;\n" + << " let inputCol = tileCol;\n" + << " " << write_data_to_sub_a_vec4_snippet + << " }\n"; + + // Load one tile of B into local memory. + shader.MainFunctionBody() + << " for (var innerRow = 0; innerRow < " << row_per_thread_b << "; innerRow = innerRow + 1) {\n" + << " let inputRow = tileRowB + innerRow;\n" + << " let inputCol = tileCol;\n" + << " mm_Bsub[inputRow][inputCol] = mm_readB(batch, kStart + inputRow, globalCol" << (nullptr != batch_dims ? ", batchIndices" : "") << ");\n" + << " }\n" + << " kStart = kStart + tileInner;\n" + << " workgroupBarrier();\n"; + + // Compute acc values for a single thread. + shader.MainFunctionBody() + << " for (var k = 0; k < tileInner / innerElementSize; k = k + 1) {\n" + << " let BCached0 = mm_Bsub[k * innerElementSize][tileCol];\n" + << " let BCached1 = mm_Bsub[k * innerElementSize + 1][tileCol];\n" + << " let BCached2 = mm_Bsub[k * innerElementSize + 2][tileCol];\n"; + + if (inner_elements_size != 3) { + shader.MainFunctionBody() << " let BCached3 = mm_Bsub[k * innerElementSize + 3][tileCol];\n"; + } + + if (transpose_a) { + shader.MainFunctionBody() + << " let Acached0 = mm_Asub[k * innerElementSize][localRow];\n" + << " let Acached1 = mm_Asub[k * innerElementSize + 1][localRow];\n" + << " let Acached2 = mm_Asub[k * innerElementSize + 2][localRow];\n" + << (inner_elements_size == 3 ? "" : " let Acached3 = mm_Asub[k * innerElementSize + 3][localRow];\n") + << " for (var i = 0; i < rowPerThread; i = i + 1) {\n" + << " let ACached = mm_Asub[tileCol][i];\n" + << " acc[i] = BCached0 * ACached0[i] + acc[i];\n" + << " acc[i] = BCached1 * ACached1[i] + acc[i];\n" + << " acc[i] = BCached2 * ACached2[i] + acc[i];\n" + << " " << (inner_elements_size == 3 ? "" : "acc[i] = BCached3 * ACached3[i] + acc[i];") << "\n" + << " }\n"; + } else { + shader.MainFunctionBody() + << " for (var i = 0; i < rowPerThread; i = i + 1) {\n" + << " let ACached = mm_Asub[tileRow + i][k];\n" + << " acc[i] = BCached0 * ACached.x + acc[i];\n" + << " acc[i] = BCached1 * ACached.y + acc[i];\n" + << " acc[i] = BCached2 * ACached.z + acc[i];\n" + << " " << (inner_elements_size == 3 ? "" : "acc[i] = BCached3 * ACached.w + acc[i];") << "\n" + << " }\n"; + } + shader.MainFunctionBody() << " workgroupBarrier();\n" + << " }\n"; // main for loop + + // Write the results to the output buffer + shader.MainFunctionBody() + << " for (var innerRow = 0; innerRow < rowPerThread; innerRow = innerRow + 1) {\n" + << " mm_write(batch, globalRow + innerRow, globalCol, acc[innerRow]);\n" + << " }\n" + << "}\n"; + + return Status::OK(); +} + +Status MatMulProgram::MakeMatMulPackedSource(ShaderHelper& shader, + const InlinedVector& elements_per_thread, + uint32_t workgroup_size_x, + uint32_t workgroup_size_y, + const std::string& data_type, + const ShaderIndicesHelper* batch_dims, + bool transpose_a, + uint32_t tile_inner, + bool split_k, + uint32_t splitted_dim_inner, + bool sequentially_access_by_threads) { + ORT_UNUSED_PARAMETER(split_k); + ORT_UNUSED_PARAMETER(splitted_dim_inner); + + const auto elements_per_thread_x = elements_per_thread[0]; + const auto elements_per_thread_y = elements_per_thread[1]; + + const auto tile_a_outer = workgroup_size_y * elements_per_thread_y; + const auto tile_b_outer = workgroup_size_x * elements_per_thread_x; + const auto tile_a_width = tile_inner; + const auto tile_a_height = tile_a_outer; + + if (!(tile_a_height % workgroup_size_y == 0 && tile_a_width % workgroup_size_x == 0 && tile_inner % workgroup_size_y == 0)) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "tile_a_height: ", tile_a_height, " must be divisible by WorkgroupSizeY: ", workgroup_size_y, + ", tile_a_width: ", tile_a_width, " must be divisible by WorkgroupSizeX: ", workgroup_size_x, + ", tile_inner: ", tile_inner, " must be divisible by WorkgroupSizeY: ", workgroup_size_y); + } + + const auto row_per_thread_a = tile_a_height / workgroup_size_y; + const auto col_per_thread_a = tile_a_width / workgroup_size_x; + const auto row_per_thread_b = tile_inner / workgroup_size_y; + std::string write_data_to_sub_a_snippet = transpose_a ? std::string("mm_Asub[inputRow][inputCol] = mm_readA(batch, kStart + inputRow, globalRowStart + inputCol") + (batch_dims ? ", batchIndices" : "") + ");\n" + : std::string("mm_Asub[inputRow][inputCol] = mm_readA(batch, globalRowStart + inputRow, kStart + inputCol") + (batch_dims ? ", batchIndices" : "") + ");\n"; + shader.AdditionalImplementation() + << "var mm_Asub: array, " << tile_a_height << ">;\n" + << "var mm_Bsub: array, " << tile_inner << ">;\n" + << "const rowPerThread = " << elements_per_thread_y << ";\n" + << "const colPerThread = " << elements_per_thread_x << ";\n" + << "const tileInner = " << tile_inner << ";\n"; + + shader.MainFunctionBody() << " let batch = i32(global_id.z);\n" + << (nullptr != batch_dims ? " let batchIndices = " + batch_dims->OffsetToIndices("u32(batch)") + ";\n" : "") + << " let num_tiles = (uniforms.dim_inner - 1) / tileInner + 1;\n" + << " var kStart = 0;\n" + << " var acc: array, rowPerThread>;\n"; + + if (sequentially_access_by_threads) { + shader.MainFunctionBody() << "let localRow = i32(local_id.y);\n" + << "let localCol = i32(local_id.x);\n" + << "let globalRowStart = i32(workgroup_id.y) * " << tile_a_outer << ";\n" + << "let globalColStart = i32(workgroup_id.x) * " << tile_b_outer << ";\n" + << "\n" + << "// Loop over shared dimension.\n" + << "for (var t = 0; t < i32(num_tiles); t = t + 1) {\n" + << " // Load one tile of A into local memory.\n" + << " for (var inputRow = localRow; inputRow < " << tile_a_height << "; inputRow = inputRow + " << workgroup_size_y << ") {\n" + << " for (var inputCol = localCol; inputCol < " << tile_a_width << "; inputCol = inputCol + " << workgroup_size_x << ") {\n" + << " " << write_data_to_sub_a_snippet << "\n" + << " }\n" + << " }\n" + << " // Load one tile of B into local memory.\n" + << " for (var inputRow = localRow; inputRow < " << tile_inner << "; inputRow = inputRow + " << workgroup_size_y << ") {\n" + << " for (var inputCol = localCol; inputCol < " << tile_b_outer << "; inputCol = inputCol + " << workgroup_size_x << ") {\n" + << " mm_Bsub[inputRow][inputCol] = mm_readB(batch,\n" + << " kStart + inputRow,\n" + << " globalColStart + inputCol" << (batch_dims ? ", batchIndices" : "") << ");\n " + << " }\n" + << " }\n" + << " kStart = kStart + tileInner;\n" + << " workgroupBarrier();\n" + << "\n" + << " // Compute acc values for a single thread.\n" + << " var BCached : array<" << data_type << ", colPerThread>;\n" + << " for (var k = 0; k < tileInner; k = k + 1) {\n" + << " for (var inner = 0; inner < colPerThread; inner = inner + 1) {\n" + << " BCached[inner] = mm_Bsub[k][localCol + inner * " << workgroup_size_x << "];\n" + << " }\n" + << " for (var innerRow = 0; innerRow < rowPerThread; innerRow = innerRow + 1) {\n" + << " let ACached = " << (transpose_a ? "mm_Asub[k][localCol + innerRow * " + std::to_string(workgroup_size_y) + "];" : "mm_Asub[localRow + innerRow * " + std::to_string(workgroup_size_y) + "][k];") << "\n" + << " for (var innerCol = 0; innerCol < colPerThread; innerCol = innerCol + 1) {\n" + << " acc[innerRow][innerCol] = acc[innerRow][innerCol] +\n" + << " ACached * BCached[innerCol];\n" + << " }\n" + << " }\n" + << " }\n" + << " workgroupBarrier();\n" + << "}\n" + << "for (var innerRow = 0; innerRow < rowPerThread; innerRow = innerRow + 1) {\n" + << " let gRow = globalRowStart + localRow + innerRow * " << workgroup_size_y << ";\n" + << " for (var innerCol = 0; innerCol < colPerThread; innerCol = innerCol + 1) {\n" + << " let gCol = globalColStart + localCol + innerCol * " << workgroup_size_x << ";\n" + << " mm_write(batch, gRow, gCol, acc[innerRow][innerCol]);\n" + << " }\n" + << "}\n"; + } else { + shader.MainFunctionBody() + << "let tileRow = i32(local_id.y) * rowPerThread;\n" + << "let tileCol = i32(local_id.x) * colPerThread;\n" + << "let globalRow = i32(global_id.y) * rowPerThread;\n" + << "let globalCol = i32(global_id.x) * colPerThread;\n" + << "let globalRowStart = i32(workgroup_id.y) * " << tile_a_outer << ";\n" + << "let tileRowA = i32(local_id.y) * " << row_per_thread_a << ";\n" + << "let tileColA = i32(local_id.x) * " << col_per_thread_a << ";\n" + << "let tileRowB = i32(local_id.y) * " << row_per_thread_b << ";\n"; + + // Loop over shared dimension. + shader.MainFunctionBody() + << "for (var t = 0; t < i32(num_tiles); t = t + 1) {\n"; + + // Load one tile of A into local memory. + shader.MainFunctionBody() + << " for (var innerRow = 0; innerRow < i32(" << row_per_thread_a << "); innerRow = innerRow + 1) {\n" + << " for (var innerCol = 0; innerCol < i32(" << col_per_thread_a << "); innerCol = innerCol + 1) {\n" + << " let inputRow = tileRowA + innerRow;\n" + << " let inputCol = tileColA + innerCol;\n" + << " " << write_data_to_sub_a_snippet << "\n" + << " }\n" + << " }\n"; + + // Load one tile of B into local memory. + shader.MainFunctionBody() + << " for (var innerRow = 0; innerRow < i32(" << row_per_thread_b << "); innerRow = innerRow + 1) {\n" + << " for (var innerCol = 0; innerCol < i32(colPerThread); innerCol = innerCol + 1) {\n" + << " let inputRow = tileRowB + innerRow;\n" + << " let inputCol = tileCol + innerCol;\n" + << " mm_Bsub[inputRow][inputCol] = mm_readB(batch, kStart + inputRow, globalCol + innerCol" << (nullptr != batch_dims ? ", batchIndices" : "") << ");\n" + << " }\n" + << " }\n" + << " kStart = kStart + tileInner;\n" + << " workgroupBarrier();\n"; + + // Compute acc values for a single thread. + shader.MainFunctionBody() + << "var BCached: array<" << data_type << ", colPerThread>;\n" + << " for (var k = 0; k < tileInner; k = k + 1) {\n" + << " for (var inner = 0; inner < i32(colPerThread); inner = inner + 1) {\n" + << " BCached[inner] = mm_Bsub[k][tileCol + inner];\n" + << " }\n" + << " for (var innerRow = 0; innerRow < i32(rowPerThread); innerRow = innerRow + 1) {\n" + << " let ACached = mm_Asub[tileRow + innerRow][k];\n" + << " for (var innerCol = 0; innerCol < i32(colPerThread); innerCol = innerCol + 1) {\n" + << " acc[innerRow][innerCol] = acc[innerRow][innerCol] + ACached * BCached[innerCol];\n" + << " }\n" + << " }\n" + << " }\n" + << " workgroupBarrier();\n" + << "}\n"; + + // Write the results to the output buffer + shader.MainFunctionBody() + << "for (var innerRow = 0; innerRow < i32(rowPerThread); innerRow = innerRow + 1) {\n" + << " for (var innerCol = 0; innerCol < i32(colPerThread); innerCol = innerCol + 1) {\n" + << " mm_write(batch, globalRow + innerRow, globalCol + innerCol, acc[innerRow][innerCol]);\n" + << " }\n" + << "}\n"; + } + return Status::OK(); +} + +Status MatMulProgram::GenerateShaderCode(ShaderHelper& shader) const { + const auto& a = shader.AddInput("a", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias); + const auto& b = shader.AddInput("b", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseValueTypeAlias); + const auto& output = shader.AddOutput("output", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias); + const auto& batch_dims = shader.AddIndices("batch_dims", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias); + + if (has_bias_) { + shader.AddInput("bias", ShaderUsage::UseUniform); + } + std::string apply_activation = GetActivationSnippet(activation_, "output_value_t", "output_element_t"); + // declare the read and write functions + MatMulReadWriteFnSource(shader, a, b, output, batch_dims, apply_activation); + std::string data_type = "a_element_t"; + // generate the main function + if (is_vec4_) { + ORT_RETURN_IF_ERROR(MakeMatMulPackedVec4Source(shader, elements_per_thread_, WorkgroupSizeX(), WorkgroupSizeY(), data_type, &batch_dims)); + } else { + ORT_RETURN_IF_ERROR(MakeMatMulPackedSource(shader, elements_per_thread_, WorkgroupSizeX(), WorkgroupSizeY(), data_type, &batch_dims)); + } + return Status::OK(); +} + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/math/matmul_packed.h b/onnxruntime/core/providers/webgpu/math/matmul_packed.h new file mode 100644 index 0000000000000..d3a68ff8a57fa --- /dev/null +++ b/onnxruntime/core/providers/webgpu/math/matmul_packed.h @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/webgpu/webgpu_kernel.h" +#include "core/providers/webgpu/program.h" +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/math/matmul_utils.h" +#include "core/providers/webgpu/nn/fuse_utils.h" + +namespace onnxruntime { +namespace webgpu { +class MatMulProgram final : public Program { + public: + MatMulProgram(const Activation& activation, bool bias, bool is_vec4, const gsl::span& elements_per_thread, bool is_channels_last = false) : Program{"MatMul"}, + activation_(activation), + has_bias_{bias}, + is_vec4_{is_vec4}, + elements_per_thread_(elements_per_thread.begin(), elements_per_thread.end()), + is_channels_last_(is_channels_last) {} + + Status GenerateShaderCode(ShaderHelper& sh) const override; + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"dim_a_outer", ProgramUniformVariableDataType::Uint32}, + {"dim_b_outer", ProgramUniformVariableDataType::Uint32}, + {"dim_inner", ProgramUniformVariableDataType::Uint32}); + + static Status MakeMatMulPackedVec4Source(ShaderHelper& shader, + const InlinedVector& elements_per_thread, + uint32_t workgroup_size_x, + uint32_t workgroup_size_y, + const std::string& data_type, + const ShaderIndicesHelper* batch_dims, + bool transpose_a = false, + uint32_t tile_inner = 32, + bool split_k = false, + uint32_t splitted_dim_inner = 32); + static Status MakeMatMulPackedSource(ShaderHelper& shader, + const InlinedVector& elements_per_thread, + uint32_t workgroup_size_x, + uint32_t workgroup_size_y, + const std::string& data_type, + const ShaderIndicesHelper* batch_dims, + bool transpose_a = false, + uint32_t tile_inner = 32, + bool split_k = false, + uint32_t splitted_dim_inner = 32, + bool sequentially_access_by_threads = false); + + private: + const Activation& activation_; + const bool has_bias_; + const bool is_vec4_; + const InlinedVector elements_per_thread_; + bool is_channels_last_ = false; + void MatMulReadWriteFnSource(ShaderHelper& shader, const ShaderVariableHelper& a, const ShaderVariableHelper& b, const ShaderVariableHelper& output, const ShaderIndicesHelper& batch_dims, std::string apply_activation) const; +}; + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/math/matmul_utils.h b/onnxruntime/core/providers/webgpu/math/matmul_utils.h new file mode 100644 index 0000000000000..bcd9c1b24a9bf --- /dev/null +++ b/onnxruntime/core/providers/webgpu/math/matmul_utils.h @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/common/inlined_containers.h" +#include "core/providers/cpu/tensor/utils.h" +#include "core/providers/webgpu/shader_helper.h" + +namespace onnxruntime { +namespace webgpu { + +// Helper that creates a new TensorShape for the intermediate result of MatMul +// The new shape is created by appending the two dimensions dim1 and dim2 / components to the original shape +inline TensorShape CreateMatMulIntermediateShape(const TensorShape& shape, const int64_t dim1, const int64_t dim2, const int components) { + TensorShapeVector shape_vec = shape.AsShapeVector(); + shape_vec.push_back(dim1); + shape_vec.push_back(dim2 / components); + return TensorShape(shape_vec); +} + +// Helper that convert output batch indices to input batch indices using only the rank and +// the shape information in uniform +inline std::string ConvertOutputBatchIndicesToInputBatchIndices(const std::string& name, const ShaderVariableHelper& input, int input_batch_rank, int output_batch_rank, const std::string& batch_indices) { + std::ostringstream oss; + const std::string input_shape = "uniforms." + name + "_shape"; + const std::string input_indices = name + "_indices"; + int extending_input_rank = output_batch_rank - input_batch_rank; + for (int i = 0; i < input_batch_rank; ++i) { + oss << "if (" << GetElementAt(input_shape, i, input.Rank()) << " != 1) {\n" + << input.IndicesSet(input_indices, i, GetElementAt(batch_indices, i + extending_input_rank, output_batch_rank)) << "\n" + << "} else {\n" + << input.IndicesSet(input_indices, i, 0) << "\n" + << "}\n"; + } + return oss.str(); +} + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/math/softmax.cc b/onnxruntime/core/providers/webgpu/math/softmax.cc new file mode 100644 index 0000000000000..178ca0b9e0515 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/math/softmax.cc @@ -0,0 +1,221 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include + +#include "core/common/inlined_containers.h" +#include "core/providers/common.h" +#include "core/providers/webgpu/math/softmax.h" +#include "core/providers/webgpu/tensor/transpose.h" +#include "core/providers/cpu/tensor/utils.h" +#include "core/providers/webgpu/shader_variable.h" +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/webgpu_supported_types.h" +#include "core/providers/webgpu/webgpu_utils.h" +namespace onnxruntime { +namespace webgpu { + +ONNX_OPERATOR_VERSIONED_KERNEL_EX( + Softmax, + kOnnxDomain, + 1, 10, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T", WebGpuSupportedNumberTypes()), + Softmax); + +ONNX_OPERATOR_VERSIONED_KERNEL_EX( + Softmax, + kOnnxDomain, + 11, 12, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T", WebGpuSupportedNumberTypes()), + Softmax); + +ONNX_OPERATOR_KERNEL_EX( + Softmax, + kOnnxDomain, + 13, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T", WebGpuSupportedNumberTypes()), + Softmax); + +static std::string MaxVector(const std::string& name, int components) { + switch (components) { + case 1: + return name; + case 2: + return "max(" + name + ".x, " + name + ".y)"; + case 3: + return "max(max(" + name + ".x, " + name + ".y), " + name + ".z)"; + case 4: + return "max(max(" + name + ".x, " + name + ".y), max(" + name + ".z, " + name + ".w))"; + default: + ORT_THROW("Unsupported number of components: ", components); + } +} + +Status SoftmaxProgram::GenerateShaderCode(ShaderHelper& shader) const { + // Add input and output variables + const auto& input = shader.AddInput("x", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseValueTypeAlias); + shader.AddOutput("result", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias); + int components = input.NumComponents(); + + const std::string thread_max_decl = is_fp32_ + ? "var thread_max = x_value_t(-3.402823e+38f);\n" + : "var thread_max = x_value_t(-65504.0h);\n"; + + // Define shared memory for row max and row sum + shader.AdditionalImplementation() + << "var row_max_shared : x_value_t;\n" + << "var row_sum_shared : x_value_t;\n" + << "var thread_shared : array;\n"; + + // Define helper functions to get and set values + shader.AdditionalImplementation() + << "fn getValue(row: i32, col: i32, row_stride: i32) -> x_value_t {\n" + << " let index = row * row_stride + col;\n" + << " return x[index];\n" + << "}\n" + << "fn setValue(row: i32, col: i32, row_stride: i32, value: x_value_t) {\n" + << " let index = row * row_stride + col;\n" + << " result[index] = value;\n" + << "}\n"; + + // Main function body + shader.MainFunctionBody() + << " let gindex = i32(global_idx);\n" + << " let lindex = i32(local_idx);\n" + << " const wg = " << wg_ << ";\n" + << " let row = gindex / wg;\n" + << " let cols = uniforms.packedCols;\n" + << " let row_stride : i32 = uniforms.packedCols;\n" + + // Find the row's max value + << thread_max_decl + << " for (var col = lindex; col < cols; col += wg) {\n" + << " let value = getValue(row, col, row_stride);\n" + << " thread_max = max(thread_max, value);\n" + << " }\n" + << " if (lindex < cols) {\n" + << " thread_shared[lindex] = thread_max;\n" + << " }\n" + << " workgroupBarrier();\n" + + // Reduce to find the max value + << " var reduce_size = min(cols, wg);\n" + << " for (var curr_size = reduce_size >> 1; curr_size > 0; curr_size = reduce_size >> 1) {\n" + << " reduce_size = curr_size + (reduce_size & 1);\n" + << " if (lindex < curr_size) {\n" + << " thread_shared[lindex] = max(thread_shared[lindex], thread_shared[lindex + reduce_size]);\n" + << " }\n" + << " workgroupBarrier();\n" + << " }\n" + << " if (lindex == 0) {\n" + << " row_max_shared = x_value_t(" << MaxVector("thread_shared[0]", components) << ");\n" + << " }\n" + << " workgroupBarrier();\n" + + // Find the row's sum of exponentials + << " var thread_sum = x_value_t(0.0);\n" + << " for (var col = lindex; col < cols; col += wg) {\n" + << " let sub_exp = exp(getValue(row, col, row_stride) - row_max_shared);\n" + << " thread_sum += sub_exp;\n" + << " }\n" + << " thread_shared[lindex] = thread_sum;\n" + << " workgroupBarrier();\n" + + // Reduce to find the sum of exponentials + << " for (var curr_size = wg >> 1; curr_size > 0; curr_size = curr_size >> 1) {\n" + << " if (lindex < curr_size) {\n" + << " thread_shared[lindex] = thread_shared[lindex] + thread_shared[lindex + curr_size];\n" + << " }\n" + << " workgroupBarrier();\n" + << " }\n" + << " if (lindex == 0) {\n" + << " row_sum_shared = x_value_t(" << SumVector("thread_shared[0]", components) << ");\n" + << " }\n" + << " workgroupBarrier();\n" + + // Calculate the final value for each element in the row + << " for (var col = lindex; col < cols; col += wg) {\n" + << " let value = exp(getValue(row, col, row_stride) - row_max_shared) / row_sum_shared;\n" + << " setValue(row, col, row_stride, value);\n" + << " }\n"; + + return Status::OK(); +} + +Status Softmax::ComputeInternal(ComputeContext& context) const { + const auto* input_tensor = context.Input(0); + const TensorShape& input_shape = input_tensor->Shape(); + size_t input_rank = input_shape.NumDimensions(); + auto* output_tensor = context.Output(0, input_shape); + + // normalize axis + size_t axis = static_cast(HandleNegativeAxis(axis_, input_rank)); + // The `axis` attribute of the opset lower than version 13 describes the axis of the inputs when coerced to 2D, + // the 0th axis most likely describes the batch_size, so transpose is not required on old opset versions. + bool is_transpose_required = axis < input_rank - 1 && opset_ >= 13; + + TensorShape transposed_input_shape; + Tensor transposed_input_tensor; + Tensor intermediate_output; + InlinedVector perm(input_rank); + + if (is_transpose_required) { + std::iota(std::begin(perm), std::end(perm), 0); + perm[axis] = input_rank - 1; + perm[input_rank - 1] = axis; + + TensorShapeVector transposed_input_dims; + for (auto e : perm) { + transposed_input_dims.push_back(input_shape[e]); + } + + transposed_input_shape = TensorShape(transposed_input_dims); + transposed_input_tensor = context.CreateGPUTensor(input_tensor->DataType(), transposed_input_shape); + ORT_RETURN_IF_ERROR(Transpose::DoTranspose(context, perm, *input_tensor, transposed_input_tensor)); + intermediate_output = context.CreateGPUTensor(output_tensor->DataType(), transposed_input_shape); + } + + // The `axis` attribute of the opset lower than version 13 separates input tensor's dimensions into two parts, + // one part is treated as batch size, and the other part is performed by Softmax. + const int64_t cols = is_transpose_required ? transposed_input_shape[input_rank - 1] : (opset_ >= 13 ? input_shape[input_rank - 1] : input_shape.SizeFromDimension(axis)); + const int64_t rows = input_shape.Size() / cols; + const int64_t components = GetMaxComponents(cols); + const auto packed_cols = cols / components; + uint32_t workgroup_size = rows == 1 ? 256 : 64; + // check input tensor element type is float + const bool is_fp32 = input_tensor->GetElementType() == ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT; + + SoftmaxProgram program{workgroup_size, is_fp32}; + if (is_transpose_required) { + program + .AddInputs({{&transposed_input_tensor, ProgramTensorMetadataDependency::TypeAndRank, static_cast(components)}}) + .AddOutputs({{&intermediate_output, ProgramTensorMetadataDependency::TypeAndRank, static_cast(components)}}); + } else { + program + .AddInputs({{input_tensor, ProgramTensorMetadataDependency::TypeAndRank, static_cast(components)}}) + .AddOutputs({{output_tensor, ProgramTensorMetadataDependency::TypeAndRank, static_cast(components)}}); + } + + program + .CacheHint(std::to_string(components), std::to_string(workgroup_size)) + .SetWorkgroupSize(workgroup_size) + .SetDispatchGroupSize(static_cast(rows)) + .AddUniformVariables({{static_cast(packed_cols)}}); + + ORT_RETURN_IF_ERROR(context.RunProgram(program)); + + // If transpose was required, transpose the result back + if (is_transpose_required) { + ORT_RETURN_IF_ERROR(Transpose::DoTranspose(context, perm, intermediate_output, *output_tensor)); + } + + return Status::OK(); +} +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/math/softmax.h b/onnxruntime/core/providers/webgpu/math/softmax.h new file mode 100644 index 0000000000000..532a56ff0be41 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/math/softmax.h @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/webgpu/webgpu_supported_types.h" +#include "core/providers/webgpu/webgpu_kernel.h" +#include "core/providers/webgpu/program.h" +#include "core/framework/op_kernel.h" + +namespace onnxruntime { +namespace webgpu { + +class Softmax final : public WebGpuKernel { + public: + Softmax(const OpKernelInfo& info) : WebGpuKernel{info} { + opset_ = info.node().SinceVersion(); + int64_t axis; + Status status = info.GetAttr("axis", &axis); + + if (status.IsOK()) { + axis_ = axis; + } else { + if (opset_ < 13) { + axis_ = 1; // opset-12 and below, the default axis value is 1 + } else { + axis_ = -1; // opset-13, the default axis value is -1 + } + } + } + + Status ComputeInternal(ComputeContext& context) const override; + + private: + int64_t axis_; + int opset_; +}; + +class SoftmaxProgram final : public Program { + public: + SoftmaxProgram(uint32_t wg, bool is_fp32) + : Program{"Softmax"}, wg_{wg}, is_fp32_{is_fp32} { + } + + Status GenerateShaderCode(ShaderHelper& sh) const override; + + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"packedCols", ProgramUniformVariableDataType::Int32}); + + private: + uint32_t wg_; + bool is_fp32_; +}; + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/math/unary_elementwise_ops.cc b/onnxruntime/core/providers/webgpu/math/unary_elementwise_ops.cc index eaaad206ebaf5..e16327b9facad 100644 --- a/onnxruntime/core/providers/webgpu/math/unary_elementwise_ops.cc +++ b/onnxruntime/core/providers/webgpu/math/unary_elementwise_ops.cc @@ -27,7 +27,7 @@ Status UnaryElementwise::ComputeInternal(ComputeContext& context) const { if (size == 0) { return Status::OK(); } - uint32_t vec_size = gsl::narrow((size + 3) / 4); + uint32_t vec_size = onnxruntime::narrow((size + 3) / 4); UnaryElementwiseProgram program{kernel_name_, expression_, additional_impl_, additional_usage_}; program .AddInputs({{input_tensor, ProgramTensorMetadataDependency::Type, {vec_size}, 4}}) @@ -256,26 +256,6 @@ WEBGPU_CLIP_KERNEL(MLFloat16) // activation // -class LinearUnit : public UnaryElementwise { - public: - LinearUnit(const OpKernelInfo& info, - const std::string& kernel_name, - const std::string& expression, - const std::string& additional_impl, - float default_alpha) - : UnaryElementwise{info, kernel_name, expression, additional_impl, ShaderUsage::UseElementTypeAlias} { - info.GetAttrOrDefault("alpha", &alpha_, default_alpha); - } - - Status ConfigureProgram(const ComputeContext& /*context*/, UnaryElementwiseProgram& program) const override { - program.AddUniformVariables({alpha_}); - return Status::OK(); - } - - protected: - float alpha_; -}; - #define WEBGPU_LU_IMPL(OP_TYPE, ...) \ class OP_TYPE final : public LinearUnit { \ public: \ @@ -285,17 +265,17 @@ class LinearUnit : public UnaryElementwise { WEBGPU_LU_IMPL(Elu, "elu_v(a)", EluImpl, 1.0) WEBGPU_ELEMENTWISE_KERNEL(Elu, 6, WebGpuSupportedFloatTypes()) -class Gelu : public UnaryElementwise { - public: - Gelu(const OpKernelInfo& info) - : UnaryElementwise{info, - "Gelu", - info.GetAttrOrDefault("approximate", "none") == "tanh" ? FastGeluExpr : GeluExpr, - info.GetAttrOrDefault("approximate", "none") == "tanh" ? TanhImpl : ErfImpl, - ShaderUsage::UseValueTypeAlias} { - cache_hint = info.GetAttrOrDefault("approximate", "none"); - } -}; +Gelu::Gelu(const OpKernelInfo& info) + : UnaryElementwise{info, + "Gelu", + info.GetAttrOrDefault("approximate", "none") == "tanh" ? FastGeluExpr : GeluExpr, + info.GetAttrOrDefault("approximate", "none") == "tanh" ? TanhImpl : ErfImpl, + ShaderUsage::UseValueTypeAlias} { + cache_hint = info.GetAttrOrDefault("approximate", "none"); +} + +QuickGelu::QuickGelu(const OpKernelInfo& info) + : LinearUnit{info, "QuickGelu", "quick_gelu_v(a)", QuickGeluImpl, 1.702f} {} WEBGPU_ELEMENTWISE_KERNEL(Gelu, 20, WebGpuSupportedFloatTypes()) @@ -312,4 +292,4 @@ WEBGPU_LU_IMPL(ThresholdedRelu, "select(vec4(0), a, a > vec4) -> vec4 { } )"; +constexpr const char QuickGeluImpl[] = R"( +fn quick_gelu_v(a: vec4) -> vec4 { + let one = 1.0; + let zero = 0.0; + let alpha_vec = vec4(uniforms.attr); + let v = a * alpha_vec; + var x1 : vec4; + for (var i = 0; i < 4; i = i + 1) { + if (v[i] >= zero) { + x1[i] = one / (one + exp(-v[i])); + } else { + x1[i] = one - one / (one + exp(v[i])); + } + } + return a * x1; +} +)"; + // default GELU expression, depending on ErfImpl constexpr const char GeluExpr[] = "0.5 * a * (1.0 + erf_v(a * 0.7071067811865475))"; @@ -111,4 +159,4 @@ constexpr const char GeluExpr[] = "0.5 * a * (1.0 + erf_v(a * 0.7071067811865475 constexpr const char FastGeluExpr[] = "a * (0.5 + 0.5 * tanh_v(a * (0.035677408136300125 * a * a + 0.7978845608028654)))"; } // namespace webgpu -} // namespace onnxruntime +} // namespace onnxruntime \ No newline at end of file diff --git a/onnxruntime/core/providers/webgpu/nn/activation_util.cc b/onnxruntime/core/providers/webgpu/nn/activation_util.cc new file mode 100644 index 0000000000000..b5c31d98cda93 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/nn/activation_util.cc @@ -0,0 +1,25 @@ +#include "core/providers/webgpu/nn/activation_util.h" +#include "core/common/common.h" +namespace onnxruntime { +namespace webgpu { +std::string TypeSnippet(uint32_t component, std::string data_type) { + switch (component) { + case 1: + return data_type; + case 2: + return "vec2<" + data_type + ">"; + case 3: + return "vec3<" + data_type + ">"; + case 4: + return "vec4<" + data_type + ">"; + default: + ORT_THROW("Component ", component, " is not supported."); + } +} + +std::string BiasSnippet(bool has_bias) { + return has_bias ? "value = value + getBiasByOutputCoords(coords);" : ""; +} + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/nn/activation_util.h b/onnxruntime/core/providers/webgpu/nn/activation_util.h new file mode 100644 index 0000000000000..1c9fd93e35384 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/nn/activation_util.h @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include + +namespace onnxruntime { +namespace webgpu { + +extern std::string TypeSnippet(uint32_t component, std::string data_type); +extern std::string BiasSnippet(bool has_bias); + +} // namespace webgpu +} // namespace onnxruntime \ No newline at end of file diff --git a/onnxruntime/core/providers/webgpu/nn/batch_norm.cc b/onnxruntime/core/providers/webgpu/nn/batch_norm.cc index 687f8cb0c684b..ae4057bdea173 100644 --- a/onnxruntime/core/providers/webgpu/nn/batch_norm.cc +++ b/onnxruntime/core/providers/webgpu/nn/batch_norm.cc @@ -104,6 +104,7 @@ Status BatchNormalization::ComputeInternal(ComputeContext& context) con const TensorShape& input_shape = input_tensor->Shape(); size_t input_rank = input_shape.NumDimensions(); const int components = spatial_ ? ((input_shape[input_rank - 1] % 4 == 0) ? 4 : ((input_shape[input_rank - 1] % 2 == 0) ? 2 : 1)) : 1; + const int c_components = is_nhwc && input_rank > 1 ? components : 1; auto output_dims = input_shape.AsShapeVector(); TensorShape output_shape(output_dims); @@ -123,16 +124,17 @@ Status BatchNormalization::ComputeInternal(ComputeContext& context) con BatchNormalizationProgram program{epsilon_, spatial_, format_, static_cast(components)}; program - .AddInputs({{input_tensor, ProgramTensorMetadataDependency::TypeAndRank}, - {scale, ProgramTensorMetadataDependency::TypeAndRank}, - {B, ProgramTensorMetadataDependency::TypeAndRank}, - {input_mean, ProgramTensorMetadataDependency::TypeAndRank}, - {input_var, ProgramTensorMetadataDependency::TypeAndRank}}) - .AddOutputs({output_tensor}) + .CacheHint(epsilon_, spatial_, format_, components) + .AddInputs({{input_tensor, ProgramTensorMetadataDependency::TypeAndRank, components}, + {scale, ProgramTensorMetadataDependency::TypeAndRank, c_components}, + {B, ProgramTensorMetadataDependency::TypeAndRank, c_components}, + {input_mean, ProgramTensorMetadataDependency::TypeAndRank, c_components}, + {input_var, ProgramTensorMetadataDependency::TypeAndRank, c_components}}) + .AddOutputs({{output_tensor, ProgramTensorMetadataDependency::TypeAndRank, components}}) .SetDispatchGroupSize((output_size + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE) .AddUniformVariables({{static_cast(output_size)}}); return context.RunProgram(program); } } // namespace webgpu -} // namespace onnxruntime \ No newline at end of file +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/nn/conv.cc b/onnxruntime/core/providers/webgpu/nn/conv.cc new file mode 100644 index 0000000000000..0edad3eebe2ea --- /dev/null +++ b/onnxruntime/core/providers/webgpu/nn/conv.cc @@ -0,0 +1,273 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +#include "core/providers/webgpu/nn/conv.h" +#include "core/providers/webgpu/nn/conv2d_mm_webgpu.h" +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/webgpu_supported_types.h" +#include "core/providers/webgpu/tensor/transpose.h" +#include "core/providers/webgpu/nn/grouped_conv.h" +#include "core/providers/webgpu/webgpu_utils.h" +#include "core/providers/webgpu/math/matmul.h" +namespace onnxruntime { +namespace webgpu { + +Status TransposeKernel(ComputeContext& context, const Tensor* kernel, const TensorShape& kernel_shape, Tensor* transposed_kernel, const InlinedVector& perm) { + // Transpose weights + auto rank = kernel_shape.NumDimensions(); + TensorShapeVector transposed_kernel_shape_vector(rank); + for (size_t i = 0; i < rank; ++i) { + transposed_kernel_shape_vector[i] = kernel_shape[perm[i]]; + } + uint32_t output_size = onnxruntime::narrow(kernel_shape.Size()); + TensorShape transposed_kernel_shape(transposed_kernel_shape_vector); + *transposed_kernel = context.CreateGPUTensor(kernel->DataType(), transposed_kernel_shape); + bool use_shared = false; + TransposeProgram program{perm, use_shared}; + program + .CacheHint(absl::StrJoin(perm, "-")) + .AddInput({kernel, ProgramTensorMetadataDependency::TypeAndRank, kernel_shape, 1}) + .AddOutput({transposed_kernel, ProgramTensorMetadataDependency::TypeAndRank}) + .AddUniformVariable({output_size}) + .SetDispatchGroupSize((output_size + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE); + return context.RunProgram(program); +} + +template +Status Conv::ComputeInternal(ComputeContext& context) const { + bool has_bias = context.InputCount() > 2; + const auto* input = context.Input(0); + const auto* kernel = context.Input(1); + const auto* bias = has_bias ? context.Input(2) : nullptr; + TensorShape input_shape = input->Shape(); + TensorShape kernel_shape = kernel->Shape(); + ConvAttributes::ConvPadVector local_pads(conv_attrs_.pads.begin(), conv_attrs_.pads.end()); + TensorShapeVector local_dilations(conv_attrs_.dilations.begin(), conv_attrs_.dilations.end()); + TensorShapeVector local_strides(conv_attrs_.strides.begin(), conv_attrs_.strides.end()); + TensorShapeVector kernel_spacial_shape_vector; + ORT_RETURN_IF_ERROR(conv_attrs_.ComputeKernelShape(kernel_shape, kernel_spacial_shape_vector, false)); + if (local_pads.empty()) { + local_pads.resize(kernel_spacial_shape_vector.size() * 2, 0); + } + if (local_dilations.empty()) { + local_dilations.resize(kernel_spacial_shape_vector.size(), 1); + } + if (local_strides.empty()) { + local_strides.resize(kernel_spacial_shape_vector.size(), 1); + } + TensorShapeVector input_shape_vector = input_shape.AsShapeVector(); + auto batch = input_shape[0]; + TensorShapeVector output_shape_vector = {batch}; + TensorShape input_spacial_shape = is_channels_last ? TensorShape(TensorShapeVector(std::next(input_shape_vector.begin()), std::prev(input_shape_vector.end()))) : input_shape.Slice(2); + ORT_RETURN_IF_ERROR(conv_attrs_.InferPadsAndOutputShape(input_spacial_shape, kernel_spacial_shape_vector, local_strides, local_dilations, local_pads, output_shape_vector)); + auto output_channels = kernel_shape[0]; + if (is_channels_last) { + output_shape_vector.push_back(output_channels); + } else { + output_shape_vector.insert(output_shape_vector.begin() + 1, output_channels); + } + auto output_shape = TensorShape(output_shape_vector); + auto* output = context.Output(0, output_shape); + std::vector strides; + std::vector pads; + std::vector dilations; + auto transform_dim = [](int64_t dim) { return static_cast(dim); }; + std::transform(local_pads.begin(), local_pads.end(), std::back_inserter(pads), transform_dim); + std::transform(local_strides.begin(), local_strides.end(), std::back_inserter(strides), transform_dim); + std::transform(local_dilations.begin(), local_dilations.end(), std::back_inserter(dilations), transform_dim); + auto rank = input_shape.NumDimensions(); + const InlinedVector perm = {2, 3, 1, 0}; + if (rank > 4) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Only Conv1d and Conv2d are supported."); + } else if (rank == 4) { + // Conv2D + } else if (rank == 3) { + // Conv1D + TensorShapeVector kernel_shape_vector = kernel_shape.AsShapeVector(); + input_shape_vector.insert(input_shape_vector.begin() + (is_channels_last ? 1 : 2), 1, 1); + output_shape_vector.insert(output_shape_vector.begin() + (is_channels_last ? 1 : 2), 1, 1); + kernel_shape_vector.insert(kernel_shape_vector.begin() + 2, 1); + input_shape = TensorShape(input_shape_vector); + kernel_shape = TensorShape(kernel_shape_vector); + pads.insert(pads.begin(), 0); + pads.insert(pads.begin() + 2, 0); + strides.insert(strides.begin(), 1); + dilations.insert(dilations.begin(), 1); + } else { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Input and kernel tensors must have at least 3 dimensions"); + } + std::vector inputs(has_bias ? 3 : 2); + inputs[0] = input; + inputs[1] = kernel; + if (has_bias) { + inputs[2] = bias; + } + std::vector modified_input_output_shapes = {input_shape, kernel_shape}; + if (has_bias) { + modified_input_output_shapes.push_back(bias->Shape()); + } + modified_input_output_shapes.push_back(TensorShape(output_shape_vector)); + uint32_t auto_pad_adjust = conv_attrs_.auto_pad == AutoPadType::SAME_LOWER ? 1 : 0; + auto pad0 = conv_attrs_.auto_pad == AutoPadType::NOTSET ? pads[0] : (pads[0] + pads[2] + auto_pad_adjust) / 2; + auto pad1 = conv_attrs_.auto_pad == AutoPadType::NOTSET ? pads[1] : (pads[1] + pads[3] + auto_pad_adjust) / 2; + std::vector updated_pads{pad0, pad1}; + if (conv_attrs_.group > 1) { + Tensor transposed_kernel; + if (is_channels_last) { + ORT_RETURN_IF_ERROR(TransposeKernel(context, kernel, kernel_shape, &transposed_kernel, perm)); + inputs[1] = &transposed_kernel; + modified_input_output_shapes[1] = transposed_kernel.Shape(); + } + auto output_channels_per_group = output_channels / conv_attrs_.group; + auto components = static_cast(is_channels_last && output_channels_per_group >= 4 ? GetMaxComponents(output_channels) : 1); + auto output_size = output_shape.Size() / components; + GroupedConvProgram program(activation_, has_bias, is_channels_last); + auto reduced_kernel_shape = ReduceShapeByComponents(modified_input_output_shapes[1], components); + auto reduced_output_shape = ReduceShapeByComponents(modified_input_output_shapes[has_bias ? 3 : 2], components); + program.CacheHint(activation_.ToString(), std::to_string(components), std::to_string(is_channels_last)) + .AddInput({inputs[0], ProgramTensorMetadataDependency::TypeAndRank, modified_input_output_shapes[0], 1}) + .AddInput({inputs[1], ProgramTensorMetadataDependency::TypeAndRank, reduced_kernel_shape, components}) + .AddOutput({output, ProgramTensorMetadataDependency::TypeAndRank, reduced_output_shape, components}) + .AddUniformVariables({{static_cast(output_size)}, {dilations}, {strides}, {updated_pads}, {static_cast(output_channels_per_group)}, {static_cast(components)}}) + .SetDispatchGroupSize((output_size + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE); + if (has_bias) { + auto reduced_bias_shape = ReduceShapeByComponents(modified_input_output_shapes[2], components); + program.AddInput({inputs[2], ProgramTensorMetadataDependency::TypeAndRank, reduced_bias_shape, components}); + } + return context.RunProgram(program); + } + const auto input_height = input_shape[is_channels_last ? 1 : 2]; + const auto input_width = input_shape[is_channels_last ? 2 : 3]; + const auto input_channels = input_shape[is_channels_last ? 3 : 1]; + const auto kernel_height = kernel_shape[2]; + const auto kernel_width = kernel_shape[3]; + const auto output_height = output_shape_vector[is_channels_last ? 1 : 2]; + const auto output_width = output_shape_vector[is_channels_last ? 2 : 3]; + + const auto same_size = is_channels_last && input_height == kernel_height && input_width == kernel_width && pads[0] == 0 && pads[1] == 0; + if (same_size || (kernel_height == 1 && kernel_width == 1 && pads[0] == 0 && pads[1] == 0 && strides[0] == 1 && strides[1] == 1)) { + Tensor transposed_kernel; + TensorShape input_reshape; + TensorShape kernel_reshape; + TensorShape matmul_output_shape; + std::vector matmul_inputs; + std::vector matmul_input_reshapes; + if (is_channels_last) { + // Transpose weights + + ORT_RETURN_IF_ERROR(TransposeKernel(context, kernel, kernel_shape, &transposed_kernel, perm)); + inputs[1] = &transposed_kernel; + if (same_size) { + const auto shared_dim = input_height * input_width * input_channels; + input_reshape = TensorShape({1, batch, shared_dim}); + kernel_reshape = TensorShape({1, shared_dim, output_channels}); + matmul_output_shape = TensorShape({1, batch, output_channels}); + } else { + input_reshape = TensorShape({batch, input_height * input_width, input_channels}); + kernel_reshape = TensorShape({1, input_channels, output_channels}); + matmul_output_shape = TensorShape({batch, output_height * output_width, output_channels}); + } + matmul_inputs.push_back(input); + matmul_inputs.push_back(&transposed_kernel); + matmul_input_reshapes.push_back(input_reshape); + matmul_input_reshapes.push_back(kernel_reshape); + } else { + input_reshape = TensorShape({batch, input_channels, input_height * input_width}); + kernel_reshape = TensorShape({1, output_channels, input_channels}); + matmul_output_shape = TensorShape({batch, output_channels, output_height * output_width}); + matmul_inputs.push_back(kernel); + matmul_inputs.push_back(input); + matmul_input_reshapes.push_back(kernel_reshape); + matmul_input_reshapes.push_back(input_reshape); + } + if (has_bias) { + matmul_inputs.push_back(bias); + } + auto N = matmul_output_shape[2]; + auto matmul_first_input_numdims = matmul_input_reshapes[0].NumDimensions(); + auto K = matmul_input_reshapes[0].GetDims()[matmul_first_input_numdims - 1]; + if (N < 8 && K < 8) { + const auto components = GetMaxComponents(N); + const auto a_components = GetMaxComponents(K); + const auto output_number = GetMaxComponents(output_shape[1]); + uint32_t output_size = static_cast(output_shape.Size() / components / output_number); + const size_t output_rank = matmul_output_shape.NumDimensions(); + TensorShape outer_dims = output_rank > 2 ? matmul_output_shape.Slice(0, output_rank - 2) : TensorShape({}); + MatMulNaiveProgram program(activation_, output_rank, output_number, has_bias); + program + .CacheHint(std::to_string(components), std::to_string(a_components), std::to_string(output_number)) + .AddInputs({{matmul_inputs[0], ProgramTensorMetadataDependency::TypeAndRank, ReduceShapeByComponents(matmul_input_reshapes[0], a_components), int(a_components)}, + {matmul_inputs[1], ProgramTensorMetadataDependency::TypeAndRank, ReduceShapeByComponents(matmul_input_reshapes[1], components), int(components)}}); + if (has_bias) { + program.AddInput({bias, ProgramTensorMetadataDependency::Rank, bias->Shape(), components}); + } + program + .AddOutputs({{output, ProgramTensorMetadataDependency::None, ReduceShapeByComponents(matmul_output_shape, components), int(components)}}) + .SetDispatchGroupSize(static_cast((output_size + 63) / 64)) + .AddIndices(outer_dims) + .AddUniformVariables({{output_size}, {static_cast(matmul_output_shape[1])}, {static_cast(matmul_output_shape[2])}, {static_cast(K)}}); + return context.RunProgram(program); + } else { + MatMulProgram program = CreateMatMulProgram(activation_, matmul_inputs, output, is_channels_last, matmul_input_reshapes[0], matmul_input_reshapes[1]); + return context.RunProgram(program); + } + } + const bool sequentially_access_by_threads = true; + // Transpose weights + Tensor transposed_kernel; + ORT_RETURN_IF_ERROR(TransposeKernel(context, kernel, kernel_shape, &transposed_kernel, perm)); + auto dim_a_outer = static_cast(is_channels_last ? output_height * output_width : output_channels); + auto dim_b_outer = static_cast(is_channels_last ? output_channels : output_height * output_width); + auto dim_inner = static_cast(kernel_height * kernel_width * input_channels); + inputs[1] = &transposed_kernel; + TensorShape transposed_kernel_shape = transposed_kernel.Shape(); + modified_input_output_shapes[1] = transposed_kernel.Shape(); + Conv2dMMProgram conv2d_mm_program = CreateConv2dMMProgram(activation_, inputs, pads, strides, dilations, output, dim_a_outer, dim_b_outer, dim_inner, is_channels_last, sequentially_access_by_threads, modified_input_output_shapes); + return context.RunProgram(conv2d_mm_program); +} + +// Explicit template instantiation for FusedConv +template class Conv; +template class Conv; +template class Conv; +template class Conv; + +#define WEBGPU_ONNX_CONV_OPERATOR_KERNEL(VERSION_FROM) \ + ONNX_OPERATOR_KERNEL_EX( \ + Conv, \ + kMSInternalNHWCDomain, \ + VERSION_FROM, \ + kWebGpuExecutionProvider, \ + (*KernelDefBuilder::Create()).TypeConstraint("T", WebGpuSupportedFloatTypes()), \ + Conv); \ + \ + ONNX_OPERATOR_KERNEL_EX( \ + Conv, \ + kOnnxDomain, \ + VERSION_FROM, \ + kWebGpuExecutionProvider, \ + (*KernelDefBuilder::Create()).TypeConstraint("T", WebGpuSupportedFloatTypes()), \ + Conv); + +#define WEBGPU_ONNX_CONV_OPERATOR_VERSIONED_KERNEL(VERSION_FROM, VERSION_TO) \ + ONNX_OPERATOR_VERSIONED_KERNEL_EX( \ + Conv, \ + kOnnxDomain, \ + VERSION_FROM, VERSION_TO, \ + kWebGpuExecutionProvider, \ + (*KernelDefBuilder::Create()).TypeConstraint("T", WebGpuSupportedFloatTypes()), \ + Conv); \ + \ + ONNX_OPERATOR_VERSIONED_KERNEL_EX( \ + Conv, \ + kMSInternalNHWCDomain, \ + VERSION_FROM, VERSION_TO, \ + kWebGpuExecutionProvider, \ + (*KernelDefBuilder::Create()).TypeConstraint("T", WebGpuSupportedFloatTypes()), \ + Conv); + +WEBGPU_ONNX_CONV_OPERATOR_VERSIONED_KERNEL(1, 10) +WEBGPU_ONNX_CONV_OPERATOR_VERSIONED_KERNEL(11, 21) +WEBGPU_ONNX_CONV_OPERATOR_KERNEL(22) + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/nn/conv.h b/onnxruntime/core/providers/webgpu/nn/conv.h new file mode 100644 index 0000000000000..cafaa272c0613 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/nn/conv.h @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/common/optional.h" +#include "core/providers/webgpu/webgpu_kernel.h" +#include "core/providers/cpu/nn/conv_attributes.h" +#include "core/providers/webgpu/program.h" +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/nn/fuse_utils.h" + +namespace onnxruntime { +namespace webgpu { + +template +class Conv : public WebGpuKernel { + public: + Conv(const OpKernelInfo& info) : WebGpuKernel(info), conv_attrs_(info) { + if (is_fused) { + ORT_ENFORCE(GetFusedActivationAttr(info, activation_).IsOK()); + } + } + Status ComputeInternal(ComputeContext& context) const override; + + protected: + ConvAttributes conv_attrs_; + Activation activation_; +}; + +Status TransposeKernel(ComputeContext& context, const Tensor* kernel, const TensorShape& kernel_shape, Tensor* transposed_kernel, const InlinedVector& perm); + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/nn/conv2d_mm_webgpu.cc b/onnxruntime/core/providers/webgpu/nn/conv2d_mm_webgpu.cc new file mode 100644 index 0000000000000..24e49304cf532 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/nn/conv2d_mm_webgpu.cc @@ -0,0 +1,232 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +#include +#include +#include +#include +#include "core/providers/webgpu/nn/conv2d_mm_webgpu.h" +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/webgpu_supported_types.h" +#include "core/providers/webgpu/nn/activation_util.h" +#include "core/providers/webgpu/math/matmul_packed.h" +#include "core/providers/webgpu/nn/conv_utils.h" +#include "core/providers/webgpu/nn/fuse_utils.h" +#include "core/providers/webgpu/webgpu_utils.h" + +namespace onnxruntime { +namespace webgpu { +std::string Conv2dMMProgram::Conv2dCommonSnippet(const ShaderVariableHelper& x, const ShaderVariableHelper& w, const Activation& activation, std::string data_type, uint32_t inner_element_size_x, uint32_t inner_element_size_w, uint32_t inner_element_size) const { + auto get_x_snippet = [&](int32_t inner_element_size) -> std::string { + switch (inner_element_size) { + case 1: + return "resData = " + x.GetByOffset("xIndex") + ";"; + case 3: + return "resData = vec3(" + x.GetByOffset("xIndex") + ", " + x.GetByOffset("xIndex + 1") + ", " + x.GetByOffset("xIndex + 2") + ");"; + case 4: + return "resData = " + x.GetByOffset("xIndex") + ";\n "; + default: + ORT_THROW("inner_element_size", inner_element_size, " is not supported."); + } + }; + auto get_w_snippet = [&](int32_t inner_element_size) -> std::string { + switch (inner_element_size) { + case 1: + return "return " + w.GetByOffset("row * i32(uniforms.w_shape[3]) + colIn") + ";\n"; + case 4: + return "return " + w.GetByOffset("row * i32(uniforms.w_shape[3]) + colIn") + ";\n"; + default: + ORT_THROW("inner_element_size ", inner_element_size, " is not supported."); + } + }; + const std::string coord_a_snippet = is_channels_last_ ? "let coord = vec4(batch, xRow, xCol, xCh / " + std::to_string(inner_element_size_x == 3 ? 4 : inner_element_size_x) + ");" : "let coord = vec4(batch, xCh, xRow, xCol);"; + const std::string coord_res_snippet = is_channels_last_ ? "let coords = vec4(batch, row / outWidth, row % outWidth, col / " + std::to_string(inner_element_size) + ");" : "let coords = vec4(batch, row, col / outWidth, col % outWidth);"; + + const std::string xHeight = is_channels_last_ ? "i32(uniforms.x_shape[1])" : "i32(uniforms.x_shape[2])"; + const std::string xWidth = is_channels_last_ ? "i32(uniforms.x_shape[2])" : "i32(uniforms.x_shape[3])"; + const std::string row = is_channels_last_ ? "row" : "col"; + const std::string col = is_channels_last_ ? "col" : "row"; + std::stringstream read_x_snippet; + read_x_snippet + << "let inChannels = i32(uniforms.w_shape[2]);\n" + << "let outWidth = " << (is_channels_last_ ? "i32(uniforms.result_shape[2])" : "i32(uniforms.result_shape[3])") << ";\n" + << "let outRow = " << row << " / outWidth;\n " + << "let outCol = " << row << " % outWidth;\n" + << "let WRow = " << col << " / (i32(uniforms.w_shape[1]) * inChannels);\n" + << "let WCol = " << col << " / inChannels % i32(uniforms.w_shape[1]);\n" + << "let xRow = outRow * i32(uniforms.strides[0]) + i32(uniforms.dilations[0]) * WRow - i32(uniforms.pads[0]);\n" + << "let xCol = outCol * i32(uniforms.strides[1]) + i32(uniforms.dilations[1]) * WCol - i32(uniforms.pads[1]);\n" + << "let xCh = " << col << " % inChannels;\n" + << "var resData = " << TypeSnippet(inner_element_size_x, data_type) << "(0.0);\n " + << "// The bounds checking is always needed since we use it to pad zero for\n" + << "// the \" same \" padding type.\n" + << "if (xRow >= 0 && xRow < " << xHeight << " && xCol >= 0 && xCol < " << xWidth << ") {\n" + << " " << coord_a_snippet << "\n" + << " let xIndex = getIndexFromCoords4D(coord, vec4(uniforms.x_shape));\n" + << " " << get_x_snippet(inner_element_size_x) + << "}\n" + << "return resData;"; + std::stringstream sample_x; + if (is_channels_last_) { + if (fit_a_outer_ && fit_inner_) { + sample_x << "let col = colIn * " << inner_element_size_x << ";\n" + << read_x_snippet.str(); + } else { + sample_x << "let col = colIn * " << inner_element_size_x << ";\n" + << "if(row < i32(uniforms.dim_a_outer) && col < i32(uniforms.dim_inner)) {\n" + << " " << read_x_snippet.str() << "\n" + << "}\n" + << "return " << TypeSnippet(inner_element_size_x, data_type) << "(0.0);\n"; + } + } else { + if (fit_inner_ && fit_b_outer_) { + sample_x << "let col = colIn * " << inner_element_size_x << ";\n" + << read_x_snippet.str(); + } else { + sample_x << "let col = colIn * " << inner_element_size_x << ";\n" + << "if (row < i32(uniforms.dim_inner) && col < i32(uniforms.dim_b_outer)) {\n" + << " " << read_x_snippet.str() << "\n" + << "}\n" + << "return " << TypeSnippet(inner_element_size_x, data_type) << "(0.0);\n"; + } + } + std::stringstream sample_w; + if (is_channels_last_) { + if (fit_inner_ && fit_b_outer_) { + sample_w << get_w_snippet(inner_element_size_w); + } else { + sample_w << "let col = colIn * " << inner_element_size_w << ";\n" + << "if(row < i32(uniforms.dim_inner) && col < i32(uniforms.dim_b_outer)) {\n" + << " " << get_w_snippet(inner_element_size_w) << "\n" + << "}\n" + << "return " << TypeSnippet(inner_element_size_w, data_type) << "(0.0);\n"; + } + } else { + sample_w << "let col = colIn * " << inner_element_size_w << ";\n" + << "if (row < i32(uniforms.dim_inner) && col < i32(uniforms.dim_b_outer)) {\n" + << " " << get_w_snippet(inner_element_size_w) << "\n" + << "}\n" + << "return " << TypeSnippet(inner_element_size_w, data_type) << "(0.0);\n"; + } + const std::string res_type = TypeSnippet(inner_element_size, data_type); + const std::string a_type = is_channels_last_ ? TypeSnippet(inner_element_size_x, data_type) : TypeSnippet(inner_element_size_w, data_type); + const std::string b_type = is_channels_last_ ? TypeSnippet(inner_element_size_w, data_type) : TypeSnippet(inner_element_size_x, data_type); + const std::string apply_activation = GetActivationSnippet(activation, res_type, data_type); + std::stringstream user_code; + user_code << "fn mm_readA(batch : i32, row : i32, colIn : i32) -> " << a_type << " {\n" + << (is_channels_last_ ? sample_x.str() : sample_w.str()) + << "}\n" + << "\n" + << "fn mm_readB(batch : i32, row : i32, colIn : i32) -> " << b_type << " {\n" + << (is_channels_last_ ? sample_w.str() : sample_x.str()) + << "}\n" + << "\n" + << "fn mm_write(batch : i32, row : i32, colIn : i32, valueIn : " << res_type << ") {\n" + << " let col = colIn * " << inner_element_size << ";\n" + << " if(row < i32(uniforms.dim_a_outer) && col < i32(uniforms.dim_b_outer)) {\n" + << " var value = valueIn;\n" + << " let outWidth = " << (is_channels_last_ ? " i32(uniforms.result_shape[2]) " : " i32(uniforms.result_shape[3]) ") << ";\n" + << " " << coord_res_snippet << "\n" + << " " << BiasSnippet(has_bias_) << "\n" + << " " << apply_activation << "\n" + << " setOutputAtCoords(coords[0], coords[1], coords[2], coords[3], value);\n" + << " }\n" + << "}\n"; + return user_code.str(); +} + +Status Conv2dMMProgram::GenerateShaderCode(ShaderHelper& shader) const { + std::stringstream declaration_functions; + declaration_functions << "fn setOutputAtIndex(flatIndex : i32, value : " << (is_vec4_ ? "vec4" : "x_element_t") << ") {\n" + << " result[flatIndex] = " << (is_vec4_ ? "vec4" : "x_element_t") << "(value);\n" + << "}\n" + << "fn setOutputAtCoords(d0 : i32, d1 : i32, d2 : i32, d3 : i32, value : " << (is_vec4_ ? "vec4" : "x_element_t") << "){\n" + << " let flatIndex = getOutputIndexFromCoords(vec4(d0, d1, d2, d3));\n" + << " setOutputAtIndex(flatIndex, value);\n" + << "}\n"; + const auto& x = shader.AddInput("x", ShaderUsage::UseUniform | ShaderUsage::UseShapeAndStride | ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias); + const auto& w = shader.AddInput("w", ShaderUsage::UseUniform | ShaderUsage::UseShapeAndStride | ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseValueTypeAlias); + std::vector inputs = {&x, &w}; + ORT_IGNORE_RETURN_VALUE(shader.AddOutput("result", ShaderUsage::UseUniform | ShaderUsage::UseShapeAndStride | ShaderUsage::UseIndicesTypeAlias)); + if (has_bias_) { + const auto& bias = shader.AddInput("bias", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias); + inputs.push_back(&bias); + declaration_functions << "fn getBiasByOutputCoords(coords : vec4) -> bias_value_t {" << "\n" + << " return bias[" << (is_channels_last_ ? "coords.w" : "coords.y") << "];\n" + << "}"; + } + shader.AdditionalImplementation() + << UtilFunctions("uniforms.result_stride") + << declaration_functions.str() + << Conv2dCommonSnippet(x, w, activation_, "x_element_t", element_size_[0], element_size_[1], element_size_[2]); + std::string data_type = "x_element_t"; + return is_vec4_ ? MatMulProgram::MakeMatMulPackedVec4Source(shader, elements_per_thread_, WorkgroupSizeX(), WorkgroupSizeY(), data_type, /* batch_dims = */ nullptr, /* transpose_a = */ !is_channels_last_, tile_inner_) : MatMulProgram::MakeMatMulPackedSource(shader, elements_per_thread_, WorkgroupSizeX(), WorkgroupSizeY(), data_type, /* batch_dims = */ nullptr, false, tile_inner_, false, 0, sequentially_access_by_threads_); +} + +Conv2dMMProgram CreateConv2dMMProgram(const Activation& activation, const std::vector& inputs, const std::vector& pads, const std::vector& strides, const std::vector& dilations, Tensor* output, uint32_t dim_a_outer, uint32_t dim_b_outer, uint32_t dim_inner, bool is_channels_last, bool sequentially_access_by_threads, const std::vector& input_output_shapes) { + const auto* input = inputs[0]; + const auto* weight = inputs[1]; + bool has_bias = inputs.size() > 2; + const auto* bias = has_bias ? inputs[2] : nullptr; + const auto& input_shape = input_output_shapes[0]; + auto in_channels = is_channels_last ? input_shape[3] : input_shape[1]; + const auto& output_shape = has_bias ? input_output_shapes[3] : input_output_shapes[2]; + auto batch_size = output_shape[0]; + const auto output_width = is_channels_last ? output_shape[2] : output_shape[3]; + const auto output_height = is_channels_last ? output_shape[1] : output_shape[2]; + const auto output_channels = is_channels_last ? output_shape[3] : output_shape[1]; + // TODO: enable vec4 for NCHW + const bool is_vec4 = is_channels_last && (in_channels % 4 == 0 || in_channels % 3 == 0) && output_channels % 4 == 0; + + // TODO: fine tune size + const auto dispatch_x = is_channels_last ? output_channels : output_width * output_height; + const auto dispatch_y = is_channels_last ? output_width * output_height : output_channels; + std::vector workgroup_size = {8, 8, 1}; + InlinedVector elements_per_thread = {4, static_cast(dim_a_outer <= 8 ? 1 : 4), 1}; + auto integer_ceil = [](int64_t a, int64_t b) -> int64_t { return (a + b - 1) / b; }; + + const std::vector dispatch = { + static_cast(integer_ceil(integer_ceil(dispatch_x, workgroup_size[0]), elements_per_thread[0])), + static_cast(integer_ceil(integer_ceil(dispatch_y, workgroup_size[1]), elements_per_thread[1])), + static_cast(integer_ceil(integer_ceil(batch_size, workgroup_size[2]), elements_per_thread[2])), + }; + + uint32_t inner_element_size = is_vec4 ? (is_channels_last && in_channels % 4 != 0 ? 3 : 4) : 1; + auto tile_a_outer = static_cast(workgroup_size[1] * elements_per_thread[1]); + auto tile_b_outer = static_cast(workgroup_size[0] * elements_per_thread[0]); + auto tile_inner = std::max(workgroup_size[0] * inner_element_size, workgroup_size[1]); + bool fit_a_outer = dim_a_outer % tile_a_outer == 0; + bool fit_b_outer = dim_b_outer % tile_b_outer == 0; + bool fit_inner = dim_inner % tile_inner == 0; + std::vector element_size = {is_vec4 ? inner_element_size : 1, static_cast(is_vec4 ? 4 : 1), static_cast(is_vec4 ? 4 : 1)}; + const auto components = is_vec4 ? 4 : 1; + const auto input_components = static_cast(inner_element_size == 3 ? 1 : inner_element_size); + Conv2dMMProgram program(activation, tile_inner, fit_a_outer, fit_b_outer, fit_inner, is_channels_last, is_vec4, has_bias, std::move(element_size), std::move(elements_per_thread), sequentially_access_by_threads); + TensorShape reduced_input_shape = ReduceShapeByComponents(input_output_shapes[0], input_components); + TensorShape reduced_weight_shape = ReduceShapeByComponents(input_output_shapes[1], components); + TensorShape reduced_output_shape = ReduceShapeByComponents(input_output_shapes[has_bias ? 3 : 2], components); + program.AddInputs({{input, ProgramTensorMetadataDependency::TypeAndRank, reduced_input_shape, input_components}, {weight, ProgramTensorMetadataDependency::TypeAndRank, reduced_weight_shape, components}}); + if (has_bias) { + TensorShape reduced_bias_shape = ReduceShapeByComponents(input_output_shapes[2], components); + program.AddInput({bias, ProgramTensorMetadataDependency::TypeAndRank, reduced_bias_shape, components}); + } + const auto stringify = [](const std::vector& vec) -> std::string { + std::ostringstream oss; + std::transform(vec.begin(), vec.end(), std::ostream_iterator(oss, ","), [](uint32_t i) { return std::to_string(i); }); + return oss.str(); + }; + program.CacheHint(activation.ToString(), stringify({inner_element_size, static_cast(is_vec4 ? 1 : 0), fit_a_outer, fit_b_outer, fit_inner, tile_a_outer, tile_a_outer, tile_inner, static_cast(components)})) + .AddOutput({output, ProgramTensorMetadataDependency::TypeAndRank, reduced_output_shape, components}) + .SetDispatchGroupSize(dispatch[0], dispatch[1], dispatch[2]) + .SetWorkgroupSize(workgroup_size[0], workgroup_size[1], workgroup_size[2]) + .AddUniformVariables({{static_cast(dim_a_outer)}, + {static_cast(dim_b_outer)}, + {static_cast(dim_inner)}, + {pads}, + {strides}, + {dilations}}); + + return program; +} + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/nn/conv2d_mm_webgpu.h b/onnxruntime/core/providers/webgpu/nn/conv2d_mm_webgpu.h new file mode 100644 index 0000000000000..0087d11db179d --- /dev/null +++ b/onnxruntime/core/providers/webgpu/nn/conv2d_mm_webgpu.h @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include +#include +#include "core/common/inlined_containers.h" +#include "core/providers/webgpu/webgpu_supported_types.h" +#include "core/providers/webgpu/webgpu_kernel.h" +#include "core/providers/webgpu/program.h" +#include "core/framework/tensor_shape.h" +#include "core/framework/tensor.h" +#include "core/providers/webgpu/nn/fuse_utils.h" +#include "core/providers/webgpu/shader_helper.h" + +namespace onnxruntime { +namespace webgpu { +class Conv2dMMProgram final : public Program { + public: + Conv2dMMProgram(const Activation& activation, uint32_t tile_inner, bool fit_a_outer, bool fit_b_outer, bool fit_inner, bool is_channels_last, bool is_vec4, bool has_bias, std::vector&& element_size, InlinedVector&& elements_per_thread, bool sequentially_access_by_threads) : Program("Conv2dMM"), + activation_(activation), + tile_inner_(tile_inner), + fit_a_outer_(fit_a_outer), + fit_b_outer_(fit_b_outer), + fit_inner_(fit_inner), + is_channels_last_(is_channels_last), + is_vec4_(is_vec4), + has_bias_(has_bias), + element_size_(std::move(element_size)), + elements_per_thread_(std::move(elements_per_thread)), + sequentially_access_by_threads_(sequentially_access_by_threads) {} + + std::string Conv2dCommonSnippet(const ShaderVariableHelper& x, const ShaderVariableHelper& w, const Activation& activation, std::string data_type, uint32_t inner_element_size_x = 4, uint32_t inner_element_size_w = 4, uint32_t inner_element_size = 4) const; + Status GenerateShaderCode(ShaderHelper& sh) const override; + + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES( + {"dim_a_outer", ProgramUniformVariableDataType::Uint32}, + {"dim_b_outer", ProgramUniformVariableDataType::Uint32}, + {"dim_inner", ProgramUniformVariableDataType::Uint32}, + {"pads", ProgramUniformVariableDataType::Uint32}, + {"strides", ProgramUniformVariableDataType::Uint32}, + {"dilations", ProgramUniformVariableDataType::Uint32}); + + private: + const Activation& activation_; + uint32_t tile_inner_; + bool fit_a_outer_; + bool fit_b_outer_; + bool fit_inner_; + bool is_channels_last_; + bool is_vec4_; + bool has_bias_; + std::vector element_size_; + InlinedVector elements_per_thread_; + bool sequentially_access_by_threads_; +}; + +Conv2dMMProgram CreateConv2dMMProgram(const Activation& activation, const std::vector& inputs, const std::vector& pads, const std::vector& strides, const std::vector& dilations, Tensor* output, uint32_t dim_a_outer, uint32_t dim_b_outer, uint32_t dim_inner, bool is_channels_last, bool sequentially_access_by_threads, const std::vector& modified_input_output_shapes); + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/nn/conv_backprop_webgpu.cc b/onnxruntime/core/providers/webgpu/nn/conv_backprop_webgpu.cc new file mode 100644 index 0000000000000..74f3e0dcc85f5 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/nn/conv_backprop_webgpu.cc @@ -0,0 +1,193 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +#include +#include +#include +#include "core/common/inlined_containers.h" +#include "core/providers/webgpu/nn/conv_backprop_webgpu.h" +#include "core/providers/webgpu/webgpu_utils.h" +namespace onnxruntime { +namespace webgpu { + +Status ConvTranspose2DProgram::GenerateShaderCode(ShaderHelper& shader) const { + const auto& dy = shader.AddInput("dy", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias); + const auto& w = shader.AddInput("w", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseValueTypeAlias); + const auto& output = shader.AddOutput("output", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseValueTypeAlias); + if (has_bias_) { + shader.AddInput("bias"); + } + auto row_dim = is_channels_last_ ? 1 : 2; + auto col_dim = is_channels_last_ ? 2 : 3; + auto channel_dim = is_channels_last_ ? 3 : 1; + auto calculate_result = [&]() -> std::string { + std::stringstream ss; + if (pack_input_as4_) { + if (a_components_ == 4) { + ss << "let xValue = " << dy.GetByOffset("x_offset") << ";\n" + << "let wValue = " << w.GetByOffset("w_offset") << ";\n" + << "dotProd = dotProd + dot(xValue, wValue);\n" + << "x_offset += 1;\n" + << "w_offset += 1;\n"; + } else if (a_components_ == 2) { + ss << "let xValue = vec4(" << dy.GetByOffset("x_offset") << ", " << dy.GetByOffset("x_offset + 1") << ");\n" + << "let wValue = vec4(" << w.GetByOffset("w_offset") << ", " << w.GetByOffset("w_offset + 1u") << ");\n" + << "dotProd = dotProd + dot(xValue, wValue);\n" + << "x_offset += 2;\n" + << "w_offset += 2;\n"; + } else if (a_components_ == 1) { + ss << "let xValue = vec4(" << dy.GetByOffset("x_offset") << ", " << dy.GetByOffset("x_offset + 1u") << ", " << dy.GetByOffset("x_offset + 2u") << ", " << dy.GetByOffset("x_offset + 3u") << ");\n" + << "let wValue = vec4(" << w.GetByOffset("x_offset") << ", " << w.GetByOffset("x_offset + 1u") << ", " << w.GetByOffset("x_offset + 2u") << ", " << w.GetByOffset("x_offset + 3u") << ");\n" + << "dotProd = dotProd + dot(xValue, wValue);\n" + << "x_offset += 4;\n" + << "w_offset += 4;\n"; + } + } else { + if (is_channels_last_) { + ss << "let xValue = " << dy.GetByIndices("dy_indices_t(batch, idyR, idyC, inputChannel / " + std::to_string(a_components_)) << ");\n"; + } else { + ss << "let xValue = " << dy.GetByIndices("dy_indices_t(batch, inputChannel, idyR, idyC)") << ";\n"; + } + if (a_components_ == 1) { + ss << "let wValue = " << w.GetByIndices("w_indices_t(u32(wRPerm), u32(wCPerm), inputChannel, wOutChannel)") << ";\n" + << "dotProd = dotProd + xValue * wValue;\n"; + } else if (a_components_ == b_components_ && components_ == 1) { + ss << "let wValue = " << w.GetByIndices("w_indices_t(u32(wRPerm), u32(wCPerm), inputChannel, wOutChannel)") << ";\n" + << "dotProd = dotProd + dot(xValue, wValue);\n"; + } else { + for (uint32_t i = 0; i < a_components_; ++i) { + ss << "let w_indices" << i << " = w_indices_t(u32(wRPerm), u32(wCPerm), inputChannel + d2 + " << i << ", wOutChannel);\n " + << "let w_offset" << i << " = " << w.IndicesToOffset("w_indices" + std::to_string(i)) << ";\n" + << "let wValue" << i << " = " << w.GetByIndices("w_indices" + std::to_string(i)) << ";\n" + << "dotProd = dotProd + xValue[" << i << "] * wValue" << i << ";\n"; + } + } + } + return ss.str(); + }; + auto calculate_remainder = [&]() -> std::string { + std::stringstream ss; + if (input_channels_remainder_ > 0) { + ORT_ENFORCE(pack_input_as4_, "Invalid input_channels_remainder: ", input_channels_remainder_); + if (a_components_ == 1) { + for (uint32_t i = 0; i < input_channels_remainder_; ++i) { + ss << "dotProd = dotProd + " << dy.GetByOffset("x_offset + " + std::to_string(i)) << ";\n"; + } + } else if (a_components_ == 2) { + if (input_channels_remainder_ != 2) { + ORT_THROW("Invalid input_channels_remainder: ", input_channels_remainder_); + } + ss << "let xValue = " << dy.GetByOffset("x_offset") << ";\n" + << "let wValue = " << w.GetByOffset("w_offset") << ";\n" + << "dotProd = dotProd + dot(xValue, wValue);\n"; + } + } + return ss.str(); + }; + shader.MainFunctionBody() << shader.GuardAgainstOutOfBoundsWorkgroupSizes("uniforms.output_size") + << "let outputIndices = " << output.OffsetToIndices("global_idx") << ";\n" + << "let batch = " << output.IndicesGet("outputIndices", 0) << ";\n" + << "let d1 = " << output.IndicesGet("outputIndices", channel_dim) << ";\n" + << "let r = " << output.IndicesGet("outputIndices", row_dim) << ";\n" + << "let c = " << output.IndicesGet("outputIndices", col_dim) << ";\n" + << "let dyCorner = vec2(i32(r), i32(c)) - vec2(uniforms.pads);\n" + << "let dyRCorner = dyCorner.x;\n" + << "let dyCCorner = dyCorner.y;\n" + << "let groupId = d1 / (uniforms.output_channels_per_group / " << components_ << ");\n" + << "let wOutChannel = d1 - groupId * (uniforms.output_channels_per_group / " << components_ << ");\n" + << "// Convolve dy(?, ?, d2) with w(:, :, d1, d2) to compute dx(xR, xC, d1).\n" + << "// ? = to be determined. : = across all values in that axis.\n" + << "var dotProd = output_value_t(0.0);\n" + << "var wR: u32 = 0;\n" + << "if (uniforms.dilations.x == 1) {\n" + << " // Minimum wR >= 0 that satisfies (dyRCorner + wR) % (uniforms.strides.x) == 0\n" + << " wR = u32(((dyRCorner + i32(uniforms.strides.x) - 1) / i32(uniforms.strides.x)) * i32(uniforms.strides.x) - dyRCorner);\n" + << "}\n" + << "for (; wR < uniforms.effective_filter_dims.x; wR = wR + 1) {\n" + << " if (wR % uniforms.dilations.x != 0) {\n" + << " continue;\n" + << " }\n" + << " let dyR = (dy_element_t(dyRCorner) + dy_element_t(wR)) / dy_element_t(uniforms.strides[0]);\n" + << " let wRPerm = uniforms.filter_dims.x - 1 - wR / uniforms.dilations.x;\n" + << " if (dyR < 0.0 || dyR >= dy_element_t(uniforms.dy_shape[" << row_dim << "]) || fract(dyR) > 0.0 || wRPerm < 0) {\n" + << " continue;\n" + << " }\n" + << " let idyR: u32 = u32(dyR);\n" + << " var wC: u32 = 0;\n" + << " if (uniforms.dilations.y == 1) {\n" + << " // Minimum wC >= 0 that satisfies (dyCCorner + wC) % (uniforms.strides.y) == 0\n" + << " wC = u32(((dyCCorner + i32(uniforms.strides.y) - 1) / i32(uniforms.strides.y)) * i32(uniforms.strides.y) - dyCCorner);\n" + << " }\n" + << " for (; wC < uniforms.effective_filter_dims.y; wC = wC + 1) {\n" + << " if (wC % uniforms.dilations.y != 0) {" + << " continue;\n" + << " }\n" + << " let dyC = (dy_element_t(dyCCorner) + dy_element_t(wC)) / dy_element_t(uniforms.strides.y);\n" + << " let wCPerm = uniforms.filter_dims.y - 1 - wC / uniforms.dilations.y;\n" + << " if (dyC < 0.0 || dyC >= dy_element_t(uniforms.dy_shape[" << col_dim << "]) ||\n" + << " fract(dyC) > 0.0 || wCPerm < 0) {\n" + << " continue;\n" + << " }\n" + << " let idyC: u32 = u32(dyC);\n" + << " var inputChannel = groupId * uniforms.input_channels_per_group;\n"; + if (pack_input_as4_) { + shader.MainFunctionBody() << " let dy_indices = dy_indices_t(batch, idyR, idyC, inputChannel);\n" + << " let w_indices = w_indices_t(u32(wRPerm), u32(wCPerm), inputChannel, wOutChannel);\n" + << " var x_offset = " << dy.IndicesToOffset("dy_indices") << ";\n" + << " var w_offset = " << w.IndicesToOffset("w_indices") << ";\n"; + } + + shader.MainFunctionBody() << " for (var d2: u32 = 0; d2 < uniforms.input_channels_per_group_int; d2 = d2 + " << (pack_input_as4_ ? 4 : a_components_) << ") {\n" + << " " << calculate_result() << "\n" + << " inputChannel = inputChannel + " << (pack_input_as4_ ? 4 : 1) << ";\n" + << " }\n" + << " " << calculate_remainder() << "\n" + << " wC = wC + uniforms.strides.y - 1;\n" + << " }\n" + << " wR = wR + uniforms.strides.x - 1;\n" + << "}\n" + << "let value = dotProd" << (has_bias_ ? " + bias[d1]" : "") << ";\n" + << output.SetByOffset("global_idx", "value") << "\n"; + return Status::OK(); +} + +ConvTranspose2DProgram CreateConvTranspose2DProgram(const std::vector& inputs, const std::vector& pads, const std::vector& strides, const std::vector& dilations, Tensor* output, bool is_channels_last, const std::vector& modified_input_output_shapes, uint32_t groups) { + bool has_bias = inputs.size() > 2; + const auto* input = inputs[0]; + const auto* weight = inputs[1]; + const auto& input_shape = modified_input_output_shapes[0]; + const auto& weight_shape = modified_input_output_shapes[1]; + const auto& output_shape = modified_input_output_shapes[has_bias ? 3 : 2]; + auto input_channels_per_group = weight_shape[2] / groups; + auto output_channels_per_group = weight_shape[3]; + auto a_components = is_channels_last ? GetMaxComponents(input_channels_per_group) : 1; + bool pack_input_as4 = is_channels_last && output_channels_per_group == 1 && input_channels_per_group >= 4; + auto input_channels_per_group_int = pack_input_as4 ? ((input_channels_per_group + 3) / 4) * 4 : (input_channels_per_group / a_components) * a_components; + auto input_channels_remainder = input_channels_per_group - input_channels_per_group_int; + auto components = is_channels_last ? GetMaxComponents(output_channels_per_group) : 1; + auto b_components = is_channels_last ? (output_channels_per_group == 1 ? a_components : components) : 1; + TensorShape reduced_input_shape = ReduceShapeByComponents(input_shape, a_components); + TensorShape reduced_weight_shape = ReduceShapeByComponents(weight_shape, b_components); + TensorShape reduced_output_shape = ReduceShapeByComponents(output_shape, components); + auto output_size = reduced_output_shape.Size(); + std::vector kernel_dims = {static_cast(weight_shape[0]), static_cast(weight_shape[1])}; + std::vector effective_kernel_dims = {kernel_dims[0] + ((dilations[0] <= 1) ? 0 : ((kernel_dims[0] - 1) * (dilations[0] - 1))), kernel_dims[1] + ((dilations[1] <= 1) ? 0 : ((kernel_dims[1] - 1) * (dilations[1] - 1)))}; + std::vector local_pads = {effective_kernel_dims[0] - 1 - pads[0], effective_kernel_dims[1] - 1 - pads[1]}; + ConvTranspose2DProgram program(is_channels_last, has_bias, components, a_components, b_components, uint32_t(input_channels_remainder), pack_input_as4); + program.AddInputs({{input, ProgramTensorMetadataDependency::TypeAndRank, reduced_input_shape, a_components}, {weight, ProgramTensorMetadataDependency::TypeAndRank, reduced_weight_shape, b_components}}); + if (has_bias) { + const auto* bias = inputs[2]; + const auto& bias_shape = modified_input_output_shapes[2]; + TensorShape reduced_bias_shape = ReduceShapeByComponents(bias_shape, components); + program.AddInput({bias, ProgramTensorMetadataDependency::TypeAndRank, reduced_bias_shape, components}); + } + program.AddOutput({output, ProgramTensorMetadataDependency::Rank, reduced_output_shape, components}) + .CacheHint(std::to_string(input_channels_remainder) + "-" + std::to_string(pack_input_as4) + std::to_string(components) + + "-" + std::to_string(b_components) + "-" + std::to_string(a_components) + "-" + std::to_string(is_channels_last ? 1 : 0)) + .AddUniformVariables({{static_cast(output_size)}, {strides}, {kernel_dims}, {dilations}, {effective_kernel_dims}, {local_pads}, {static_cast(input_channels_per_group_int)}, {static_cast(input_channels_per_group)}, {static_cast(output_channels_per_group)}}) + .SetDispatchGroupSize((output_size + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE); + + return program; +} + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/nn/conv_backprop_webgpu.h b/onnxruntime/core/providers/webgpu/nn/conv_backprop_webgpu.h new file mode 100644 index 0000000000000..6c784e4825a65 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/nn/conv_backprop_webgpu.h @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include "core/common/inlined_containers.h" +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/webgpu_supported_types.h" +#include "core/providers/webgpu/webgpu_kernel.h" +#include "core/providers/webgpu/program.h" +#include "core/framework/tensor_shape.h" +#include "core/framework/tensor.h" + +namespace onnxruntime { +namespace webgpu { + +class ConvTranspose2DProgram : public Program { + public: + ConvTranspose2DProgram(bool is_channels_last, bool has_bias, uint32_t components, uint32_t a_components, uint32_t b_components, uint32_t input_channels_remainder, bool pack_input_as4) : Program("ConvTranspose2D"), is_channels_last_(is_channels_last), has_bias_(has_bias), components_(components), a_components_(a_components), b_components_(b_components), input_channels_remainder_(input_channels_remainder), pack_input_as4_(pack_input_as4) { + } + + Status GenerateShaderCode(ShaderHelper& sh) const override; + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES( + {"output_size", ProgramUniformVariableDataType::Uint32}, + {"strides", ProgramUniformVariableDataType::Uint32}, + {"filter_dims", ProgramUniformVariableDataType::Uint32}, + {"dilations", ProgramUniformVariableDataType::Uint32}, + {"effective_filter_dims", ProgramUniformVariableDataType::Uint32}, + {"pads", ProgramUniformVariableDataType::Uint32}, + {"input_channels_per_group_int", ProgramUniformVariableDataType::Uint32}, + {"input_channels_per_group", ProgramUniformVariableDataType::Uint32}, + {"output_channels_per_group", ProgramUniformVariableDataType::Uint32}); + + private: + bool is_channels_last_; + bool has_bias_; + uint32_t components_; + uint32_t a_components_; + uint32_t b_components_; + uint32_t input_channels_remainder_; + bool pack_input_as4_; +}; + +ConvTranspose2DProgram CreateConvTranspose2DProgram(const std::vector& inputs, const std::vector& pads, const std::vector& strides, const std::vector& dilations, Tensor* output, bool is_channels_last, const std::vector& modified_input_output_shapes, uint32_t groups); + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/nn/conv_transpose.cc b/onnxruntime/core/providers/webgpu/nn/conv_transpose.cc new file mode 100644 index 0000000000000..9cd290ef56013 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/nn/conv_transpose.cc @@ -0,0 +1,132 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +#include "conv.h" +#include "conv_transpose.h" +#include "core/providers/webgpu/webgpu_kernel.h" +#include "core/providers/cpu/nn/conv_attributes.h" +#include "core/providers/webgpu/webgpu_supported_types.h" +#include "core/providers/webgpu/tensor/transpose.h" +#include "core/providers/webgpu/nn/conv_backprop_webgpu.h" + +namespace onnxruntime { +namespace webgpu { +// kernel shape is the spacial dims of the filter. +// ie. filter shape with batch and channel. kernel shape dimension is 2 less than the filter dimension + +template +Status ConvTranspose::ComputeInternal(ComputeContext& context) const { + const auto* input = context.Input(0); + const auto* filter = context.Input(1); + TensorShape input_shape = input->Shape(); + TensorShape filter_shape = filter->Shape(); + const InlinedVector perm = {2, 3, 0, 1}; + TensorShapeVector local_output_padding(conv_transpose_attrs_.output_padding.begin(), conv_transpose_attrs_.output_padding.end()); + ConvAttributes::ConvPadVector local_pads(conv_transpose_attrs_.pads.begin(), conv_transpose_attrs_.pads.end()); + TensorShapeVector local_dilations(conv_transpose_attrs_.dilations.begin(), conv_transpose_attrs_.dilations.end()); + TensorShapeVector local_strides(conv_transpose_attrs_.strides.begin(), conv_transpose_attrs_.strides.end()); + TensorShapeVector kernel_shape_vector; + auto rank = input_shape.NumDimensions(); + TensorShape input_spacial_shape = input_shape.Slice(is_channels_last ? 1 : 2, is_channels_last ? rank - 1 : rank); + local_pads.reserve(2 * (input_spacial_shape.NumDimensions())); + ORT_RETURN_IF_ERROR(conv_transpose_attrs_.ComputeKernelShape(filter_shape, kernel_shape_vector, false)); + if (local_output_padding.empty()) { + local_output_padding.resize(kernel_shape_vector.size(), 0); + } + if (local_pads.empty()) { + local_pads.resize(kernel_shape_vector.size() * 2, 0); + } + if (local_dilations.empty()) { + local_dilations.resize(kernel_shape_vector.size(), 1); + } + if (local_strides.empty()) { + local_strides.resize(kernel_shape_vector.size(), 1); + } + auto group = conv_transpose_attrs_.group; + auto num_output_channels = group * filter_shape[1]; + auto batch_size = input_shape[0]; + TensorShapeVector output_shape_vector; + conv_transpose_attrs_.ComputePadsAndOutputShape(input_spacial_shape, num_output_channels, kernel_shape_vector, local_strides, local_dilations, local_output_padding, batch_size, &local_pads, &output_shape_vector, is_channels_last); + TensorShape computed_output_shape(output_shape_vector); + std::vector strides; + std::vector pads; + std::vector dilations; + auto transform_dim = [](int64_t dim) { return static_cast(dim); }; + std::transform(local_pads.begin(), local_pads.end(), std::back_inserter(pads), transform_dim); + std::transform(local_strides.begin(), local_strides.end(), std::back_inserter(strides), transform_dim); + std::transform(local_dilations.begin(), local_dilations.end(), std::back_inserter(dilations), transform_dim); + + bool has_bias = context.InputCount() > 2; + const auto* bias = has_bias ? context.Input(2) : nullptr; + if (input_shape.NumDimensions() == 3 && filter_shape.NumDimensions() == 3) { + // ConvTranspose1D + TensorShapeVector input_shape_vector = input_shape.AsShapeVector(); + TensorShapeVector filter_shape_vector = filter_shape.AsShapeVector(); + input_shape_vector.insert(input_shape_vector.begin() + (is_channels_last ? 1 : 2), 1, 1); + output_shape_vector.insert(output_shape_vector.begin() + (is_channels_last ? 1 : 2), 1, 1); + filter_shape_vector.insert(filter_shape_vector.begin() + 2, 1); + input_shape = TensorShape(input_shape_vector); + filter_shape = TensorShape(filter_shape_vector); + pads.insert(pads.begin(), 0); + pads.insert(pads.begin() + 2, 0); + strides.insert(strides.begin(), 1); + dilations.insert(dilations.begin(), 1); + } + if (input_shape.NumDimensions() > 4 || filter_shape.NumDimensions() > 4) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Only Conv2d or Conv1d are supported."); + } else if (input_shape.NumDimensions() < 2 || filter_shape.NumDimensions() < 2) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Input and kernel tensors must have at least 3 dimensions"); + } + // Transpose weights + Tensor transposed_filter; + ORT_RETURN_IF_ERROR(TransposeKernel(context, filter, filter_shape, &transposed_filter, perm)); + TensorShape output_shape(output_shape_vector); + TensorShape transposed_filter_shape = transposed_filter.Shape(); + std::vector inputs = {input, &transposed_filter}; + std::vector input_output_shapes = {input_shape, transposed_filter_shape}; + if (has_bias) { + inputs.push_back(bias); + input_output_shapes.push_back(bias->Shape()); + } + uint32_t auto_pad_adjust = conv_transpose_attrs_.auto_pad == AutoPadType::SAME_LOWER ? 1 : 0; + auto pad0 = conv_transpose_attrs_.auto_pad == AutoPadType::NOTSET ? pads[0] : (pads[0] + pads[2] + auto_pad_adjust) / 2; + auto pad1 = conv_transpose_attrs_.auto_pad == AutoPadType::NOTSET ? pads[1] : (pads[1] + pads[3] + auto_pad_adjust) / 2; + Tensor* output = context.Output(0, computed_output_shape); + input_output_shapes.push_back(output_shape); + auto program = CreateConvTranspose2DProgram(inputs, {pad0, pad1}, strides, dilations, output, is_channels_last, input_output_shapes, static_cast(conv_transpose_attrs_.group)); + return context.RunProgram(program); +} + +ONNX_OPERATOR_KERNEL_EX( + ConvTranspose, + kMSInternalNHWCDomain, + 11, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()).TypeConstraint("T", WebGpuSupportedFloatTypes()), + ConvTranspose); + +ONNX_OPERATOR_KERNEL_EX( + ConvTranspose, + kOnnxDomain, + 11, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()).TypeConstraint("T", WebGpuSupportedFloatTypes()), + ConvTranspose); + +ONNX_OPERATOR_VERSIONED_KERNEL_EX( + ConvTranspose, + kMSInternalNHWCDomain, + 1, 10, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()).TypeConstraint("T", WebGpuSupportedFloatTypes()), + ConvTranspose); + +ONNX_OPERATOR_VERSIONED_KERNEL_EX( + ConvTranspose, + kOnnxDomain, + 1, 10, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()).TypeConstraint("T", WebGpuSupportedFloatTypes()), + ConvTranspose); + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/nn/conv_transpose.h b/onnxruntime/core/providers/webgpu/nn/conv_transpose.h new file mode 100644 index 0000000000000..a97b3f5947303 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/nn/conv_transpose.h @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/webgpu/program.h" +#include "core/providers/webgpu/webgpu_kernel.h" +#include "core/providers/common.h" + +#include "core/providers/cpu/nn/conv_transpose_attributes.h" +#include "core/providers/webgpu/webgpu_kernel.h" +namespace onnxruntime { +namespace webgpu { + +template +class ConvTranspose final : public WebGpuKernel { + public: + ConvTranspose(const OpKernelInfo& info) : WebGpuKernel(info), conv_transpose_attrs_(info) { + } + Status ComputeInternal(ComputeContext& context) const override; + + protected: + ConvTransposeAttributes conv_transpose_attrs_; +}; + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/nn/conv_utils.cc b/onnxruntime/core/providers/webgpu/nn/conv_utils.cc new file mode 100644 index 0000000000000..233662c10bfb8 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/nn/conv_utils.cc @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/webgpu/nn/conv_utils.h" +namespace onnxruntime { +namespace webgpu { +std::string UtilFunctions(std::string stride_string) { + std::stringstream ss; + ss << "fn getIndexFromCoords3D(coords : vec3, shape : vec3) -> i32 {\n" + << " return dot(coords, vec3(shape.y * shape.z, shape.z, 1));\n" + << "}\n" + << "fn getIndexFromCoords4D(coords : vec4, shape : vec4) -> i32 {\n" + << " return dot(coords, vec4(shape.y * shape.z * shape.w, shape.z * shape.w, shape.w, 1));\n" + << "}\n" + << "fn getOutputIndexFromCoords(coords : vec4) -> i32 {\n" + << " return dot(coords, vec4(i32(" << stride_string << ".x), i32(" << stride_string << ".y), i32(" << stride_string << ".z), 1));\n" + << "}\n"; + return ss.str(); +} + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/nn/conv_utils.h b/onnxruntime/core/providers/webgpu/nn/conv_utils.h new file mode 100644 index 0000000000000..ad8aa868ff7f0 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/nn/conv_utils.h @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include + +namespace onnxruntime { +namespace webgpu { + +std::string UtilFunctions(std::string stride_string); + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/nn/fuse_utils.cc b/onnxruntime/core/providers/webgpu/nn/fuse_utils.cc new file mode 100644 index 0000000000000..38db604695a54 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/nn/fuse_utils.cc @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/webgpu/nn/fuse_utils.h" +#include +namespace onnxruntime { +namespace webgpu { + +Status GetFusedActivationAttr(const OpKernelInfo& info, Activation& activation) { + activation.activation_kind_ = ActivationKind::None; + + std::string activation_type; + if (info.GetAttr("activation", &activation_type).IsOK()) { + if (activation_type == "Relu") { + activation.activation_kind_ = ActivationKind::Relu; + } else if (activation_type == "Tanh") { + activation.activation_kind_ = ActivationKind::Tanh; + } else if (activation_type == "Sigmoid") { + activation.activation_kind_ = ActivationKind::Sigmoid; + } else { + // The remaining activation types have additional parameters to be pulled out. + size_t activation_params_count; + if (activation_type == "LeakyRelu") { + activation.activation_kind_ = ActivationKind::LeakyRelu; + activation_params_count = 1; + } else if (activation_type == "Clip") { + activation.activation_kind_ = ActivationKind::Clip; + activation_params_count = 2; + } else if (activation_type == "HardSigmoid") { + activation.activation_kind_ = ActivationKind::HardSigmoid; + activation_params_count = 2; + } else { + return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT, "unimplemented activation: " + activation_type); + } + + std::vector activation_params; + common::Status status = info.GetAttrs("activation_params", activation_params); + if (!status.IsOK()) { + return status; + } else if (activation_params_count != activation_params.size()) { + return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT, "activation_params count mismatch"); + } + for (size_t i = 0; i < activation_params_count; i++) { + activation.activation_params_.values_[i] = activation_params[i]; + } + } + } + + return Status::OK(); +} + +std::string GetActivationSnippet(const Activation& activation, std::string value_type, std::string base_type) { + std::string snippet; + auto base_type_cast = [base_type](float value) -> std::string { + return base_type + "(" + std::to_string(value) + ")"; + }; + auto value_type_cast = [base_type_cast, value_type](float f) -> std::string { + return value_type + "(" + base_type_cast(f) + ")"; + }; + switch (activation.activation_kind_) { + case ActivationKind::Relu: + return "value = max(value, " + value_type_cast(0.0) + ");"; + case ActivationKind::Sigmoid: + return "value = " + value_type_cast(1.0) + " / (" + value_type_cast(1.0) + " + exp(-value));"; + case ActivationKind::Clip: + return "value = clamp(value, " + value_type_cast(activation.activation_params_.Clip.minimum_) + ", " + value_type_cast(activation.activation_params_.Clip.maximum_) + ");"; + case ActivationKind::HardSigmoid: + return "value = clamp(" + value_type_cast(activation.activation_params_.HardSigmoid.alpha_) + " * value + " + value_type_cast(activation.activation_params_.HardSigmoid.beta_) + ", 0.0" + ", 1.0" + ");"; + case ActivationKind::LeakyRelu: + return "value = select(" + base_type_cast(activation.activation_params_.LeakyRelu.alpha_) + " * value, value, value >= " + value_type_cast(0.0) + ");"; + case ActivationKind::Tanh: + return "value = tanh(value);"; + default: + return ""; + } +} + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/nn/fuse_utils.h b/onnxruntime/core/providers/webgpu/nn/fuse_utils.h new file mode 100644 index 0000000000000..f5d2585bb9b45 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/nn/fuse_utils.h @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +#include +#include "core/providers/webgpu/webgpu_kernel.h" + +#pragma once +namespace onnxruntime { +namespace webgpu { +enum class ActivationKind { + None, + Relu, + Sigmoid, + Clip, + HardSigmoid, + LeakyRelu, + Tanh +}; + +using Activation = struct Activation { + std::string ToString() const { + std::stringstream oss; + oss << "ActivationKind: " << static_cast(activation_kind_) << ";"; + oss << "ActivationParams: " << activation_params_.values_[0] << ";"; + oss << "ActivationParams: " << activation_params_.values_[1] << ";"; + return oss.str(); + } + using ActivationParameters = union ActivationParameters { + struct { + float alpha_; + } LeakyRelu; + struct { + float minimum_; + float maximum_; + } Clip; + struct { + float alpha_; + float beta_; + } HardSigmoid; + float values_[2]; + }; + ActivationParameters activation_params_ = {}; + ActivationKind activation_kind_ = ActivationKind::None; +}; + +Status GetFusedActivationAttr(const OpKernelInfo& info, Activation& activation); +std::string GetActivationSnippet(const Activation& activation, std::string value_type, std::string base_type); +// Status AppendActivationUniformsData(const Activation& activation, std::vector& variables); +// Status AppendActivationUniforms(const Activation& activation, std::vector& data); + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/nn/grouped_conv.cc b/onnxruntime/core/providers/webgpu/nn/grouped_conv.cc new file mode 100644 index 0000000000000..4dc0b82cdd7eb --- /dev/null +++ b/onnxruntime/core/providers/webgpu/nn/grouped_conv.cc @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include +#include +#include "core/providers/webgpu/nn/grouped_conv.h" +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/shader_variable.h" +#include "core/providers/webgpu/nn/fuse_utils.h" + +namespace onnxruntime { +namespace webgpu { + +std::string CanculateResult(const ShaderVariableHelper& x, const ShaderVariableHelper& w, bool is_channels_last) { + std::stringstream ss; + if (is_channels_last) { + ss << "for (var wHeight: u32 = 0u; wHeight < uniforms.w_shape[0]; wHeight++) {\n" + << " let xHeight = xRCCorner.x + wHeight * uniforms.dilations[0];\n" + << " if (xHeight < 0u || xHeight >= uniforms.x_shape[1]) {\n" + << " continue;\n" + << " }\n" + << "" + << " for (var wWidth: u32 = 0u; wWidth < uniforms.w_shape[1]; wWidth++) {\n" + << " let xWidth = xRCCorner.y + wWidth * uniforms.dilations[1];\n" + << " if (xWidth < 0u || xWidth >= uniforms.x_shape[2]) {\n" + << " continue;\n" + << " }\n" + << "" + << " for (var wInChannel: u32 = 0u; wInChannel < uniforms.w_shape[2]; wInChannel++) {\n" + << " let input_channel = in_channel_offset + wInChannel;\n" + << " let x_indices = x_indices_t(batch, xHeight, xWidth, input_channel);\n" + << " let w_indices = w_indices_t(wHeight, wWidth, wInChannel, output_channel);\n" + << " let xVal = " << x.GetByIndices("x_indices") << ";\n" + << " let wVal = " << w.GetByIndices("w_indices") << ";\n" + << " value += xVal * wVal;\n" + << " }\n" + << " }\n" + << "}\n"; + } else { + ss << "for (var wInChannel: u32 = 0u; wInChannel < uniforms.w_shape[1]; wInChannel++) {\n" + << " let input_channel = in_channel_offset + wInChannel;\n" + << " for (var wHeight: u32 = 0u; wHeight < uniforms.w_shape[2]; wHeight++) {\n" + << " let xHeight = xRCCorner.x + wHeight * uniforms.dilations[0];\n" + << "" + << " if (xHeight < 0u || xHeight >= uniforms.x_shape[2]) {\n" + << " continue;\n" + << " }\n" + << "" + << " for (var wWidth: u32 = 0u; wWidth < uniforms.w_shape[3]; wWidth++) {\n" + << " let xWidth = xRCCorner.y + wWidth * uniforms.dilations[1];\n" + << " if (xWidth < 0u || xWidth >= uniforms.x_shape[3]) {\n" + << " continue;\n" + << " }\n" + << "" + << " let x_indices = x_indices_t(batch, input_channel, xHeight, xWidth);\n" + << " let w_indices = w_indices_t(output_channel, wInChannel, wHeight, wWidth);\n" + << " let xVal = " << x.GetByIndices("x_indices") << ";\n" + << " let wVal = " << w.GetByIndices("w_indices") << ";\n" + << " value += xVal * wVal;\n" + << " }\n" + << " }\n" + << "}\n"; + } + return ss.str(); +} + +Status GroupedConvProgram::GenerateShaderCode(ShaderHelper& shader) const { + const auto& x = shader.AddInput("x", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseIndicesTypeAlias); + const auto& w = shader.AddInput("w", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseIndicesTypeAlias); + const auto& output = shader.AddOutput("output", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseElementTypeAlias); + std::string apply_activation = GetActivationSnippet(activation_, "output_value_t", "output_element_t"); + shader.MainFunctionBody() << shader.GuardAgainstOutOfBoundsWorkgroupSizes("uniforms.output_size") + << "let output_indices = " << output.OffsetToIndices("global_idx") << ";\n" + << "let batch: u32 = output_indices[0];\n" + << "let output_channel: u32 = " << output.IndicesGet("output_indices", is_channels_last_ ? "3" : "1") << ";\n" + << "let xRCCorner_x: u32 = " << output.IndicesGet("output_indices", is_channels_last_ ? "1" : "2") << ";\n" + << "let xRCCorner_y: u32 = " << output.IndicesGet("output_indices", is_channels_last_ ? "2" : "3") << ";\n" + << "let xRCCorner: vec2 = vec2(xRCCorner_x, xRCCorner_y) * uniforms.strides - uniforms.pads;\n" + << "let group_id = output_channel * uniforms.components / uniforms.output_channels_per_group;\n" + << "let in_channel_offset = group_id * " << w.IndicesGet("uniforms.w_shape", is_channels_last_ ? 2 : 1) << ";\n" + << "var value: output_value_t = output_value_t(0);\n" + << CanculateResult(x, w, is_channels_last_); + if (has_bias_) { + const auto& b = shader.AddInput("b", ShaderUsage::UseUniform | ShaderUsage::UseValueTypeAlias); + shader.MainFunctionBody() << "value += " + b.GetByIndices("output_channel") + ";\n"; + } + shader.MainFunctionBody() << apply_activation << "\n"; + shader.MainFunctionBody() << output.SetByOffset("global_idx", "value"); + return Status::OK(); +} + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/nn/grouped_conv.h b/onnxruntime/core/providers/webgpu/nn/grouped_conv.h new file mode 100644 index 0000000000000..d09f9679eecf5 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/nn/grouped_conv.h @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/common/optional.h" +#include "core/providers/webgpu/webgpu_kernel.h" +#include "core/providers/cpu/nn/conv_attributes.h" +#include "core/providers/webgpu/program.h" +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/nn/fuse_utils.h" + +namespace onnxruntime { +namespace webgpu { + +class GroupedConvProgram final : public Program { + public: + GroupedConvProgram(const Activation& activation, bool has_bias, bool is_channels_last) : Program("GroupedConv"), activation_(activation), has_bias_(has_bias), is_channels_last_(is_channels_last) { + } + Status GenerateShaderCode(ShaderHelper& shader) const override; + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES( + {"output_size", ProgramUniformVariableDataType::Uint32}, + {"dilations", ProgramUniformVariableDataType::Uint32}, + {"strides", ProgramUniformVariableDataType::Uint32}, + {"pads", ProgramUniformVariableDataType::Uint32}, + {"output_channels_per_group", ProgramUniformVariableDataType::Uint32}, + {"components", ProgramUniformVariableDataType::Uint32}); + + private: + const Activation& activation_; + bool has_bias_; + bool is_channels_last_; +}; + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/nn/layer_norm.cc b/onnxruntime/core/providers/webgpu/nn/layer_norm.cc index 64172021e82f1..1c35596ea0dc4 100644 --- a/onnxruntime/core/providers/webgpu/nn/layer_norm.cc +++ b/onnxruntime/core/providers/webgpu/nn/layer_norm.cc @@ -4,39 +4,25 @@ #include "core/providers/webgpu/shader_helper.h" #include "core/providers/webgpu/webgpu_supported_types.h" +#include "core/providers/webgpu/webgpu_utils.h" #include "core/providers/webgpu/nn/layer_norm.h" namespace onnxruntime { namespace webgpu { -static int GetMaxComponents(int64_t size) { - if (size % 4 == 0) { - return 4; - } else if (size % 2 == 0) { - return 2; - } - return 1; -} - static size_t NormalizeAxis(int64_t axis, size_t tensor_rank) { int64_t rank = static_cast(tensor_rank); if (axis < -rank && axis >= rank) { ORT_THROW("invalid axis: ", axis); } - return gsl::narrow(axis < 0 ? axis + rank : axis); + return onnxruntime::narrow(axis < 0 ? axis + rank : axis); } -static std::string SumVector(std::string x, int components) { - switch (components) { - case 1: - return x; - case 2: - return "(" + x + ".x + " + x + ".y" + ")"; - case 4: - return "(" + x + ".x + " + x + ".y + " + x + ".w + " + x + ".z" + ")"; - default: - ORT_THROW("Unsupported number of components: ", components); - } +// Get a dummy override shape to bypass the program's check of shape and components for inputs and outputs. It's okay, +// as 'LayerNormProgram' doesn't actually use the override shape. +static TensorShape GetOverrideShape(const TensorShape& shape, int components) { + TensorShape override_shape{shape.Size() / components}; + return override_shape; } Status LayerNormProgram::GenerateShaderCode(ShaderHelper& shader) const { @@ -45,7 +31,13 @@ Status LayerNormProgram::GenerateShaderCode(ShaderHelper& shader) const { if (has_bias_) { shader.AddInput("bias", ShaderUsage::UseUniform); } - shader.AddOutput("output", ShaderUsage::UseUniform); + shader.AddOutput("y", ShaderUsage::UseUniform); + if (has_mean_output_) { + shader.AddOutput("mean_output", ShaderUsage::None); + } + if (has_inv_std_dev_output_) { + shader.AddOutput("inv_std_dev_output", ShaderUsage::None); + } int components = x.NumComponents(); std::string bias = (has_bias_) ? " + bias[j]" : ""; @@ -69,8 +61,14 @@ Status LayerNormProgram::GenerateShaderCode(ShaderHelper& shader) const { << "for (var j: u32 = 0; j < uniforms.norm_size_vectorized; j++) {\n" << " let f32input = f32_val_t(x[j + offset]);\n" << " let f32scale = f32_val_t(scale[j]);\n" - << " output[j + offset] = x_value_t((f32input" << simpl2 << ") * inv_std_dev * f32scale)" << bias << ";\n" + << " y[j + offset] = x_value_t((f32input" << simpl2 << ") * inv_std_dev * f32scale)" << bias << ";\n" << "}\n"; + if (has_mean_output_) { + shader.MainFunctionBody() << "mean_output[global_idx] = mean;\n"; + } + if (has_inv_std_dev_output_) { + shader.MainFunctionBody() << "inv_std_dev_output[global_idx] = inv_std_dev;\n"; + } return Status::OK(); } @@ -83,19 +81,13 @@ Status LayerNorm::ComputeInternal(onnxruntime::webgpu::ComputeContex const auto x_shape = x->Shape(); - auto* output = context.Output(0, x_shape); - - if (x_shape.Size() == 0) { - return Status::OK(); - } - const bool is_fp16 = x->GetElementType() == ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16; const size_t axis = NormalizeAxis(axis_, x_shape.NumDimensions()); - const uint32_t norm_count = gsl::narrow(x_shape.SizeToDimension(axis)); + const uint32_t norm_count = onnxruntime::narrow(x_shape.SizeToDimension(axis)); const int64_t norm_size = x_shape.SizeFromDimension(axis); const int components = GetMaxComponents(norm_size); - const uint32_t norm_size_vectorized = gsl::narrow((norm_size + components - 1) / components); + const uint32_t norm_size_vectorized = onnxruntime::narrow((norm_size + components - 1) / components); const auto scale_size = scale->Shape().Size(); const auto bias_size = (bias) ? bias->Shape().Size() : 0; @@ -106,13 +98,31 @@ Status LayerNorm::ComputeInternal(onnxruntime::webgpu::ComputeContex scale_size, " and bias size of ", bias_size); } - LayerNormProgram program{bias != nullptr, is_fp16, simplified}; + TensorShapeVector mean_dim; + for (size_t i = 0; i < x_shape.NumDimensions(); ++i) { + if (i < axis) { + mean_dim.push_back(x_shape[i]); + } else { + mean_dim.push_back(1); + } + } + TensorShape mean_shape(mean_dim); + + auto* y = context.Output(0, x_shape); + auto* mean = context.Output(1, mean_shape); + auto* inv_std_dev = context.Output(2, mean_shape); + + if (x_shape.Size() == 0) { + return Status::OK(); + } - program - .CacheHint(simplified) - .AddInputs({{x, ProgramTensorMetadataDependency::Type, components}}) - .AddInputs({{scale, ProgramTensorMetadataDependency::Type, components}}) - .AddOutputs({{output, ProgramTensorMetadataDependency::None, components}}) + LayerNormProgram program{bias != nullptr, is_fp16, simplified, mean != nullptr, inv_std_dev != nullptr}; + + program.CacheHint(simplified) + .AddInputs({{x, ProgramTensorMetadataDependency::Type, GetOverrideShape(x->Shape(), components), components}}) + .AddInputs( + {{scale, ProgramTensorMetadataDependency::Type, GetOverrideShape(scale->Shape(), components), components}}) + .AddOutputs({{y, ProgramTensorMetadataDependency::None, GetOverrideShape(y->Shape(), components), components}}) .SetDispatchGroupSize((norm_count + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE) .AddUniformVariables({ {static_cast(norm_count)}, @@ -128,27 +138,29 @@ Status LayerNorm::ComputeInternal(onnxruntime::webgpu::ComputeContex }); if (bias != nullptr) { - program.AddInput({bias, ProgramTensorMetadataDependency::Type, components}); + program.AddInput( + {bias, ProgramTensorMetadataDependency::Type, GetOverrideShape(bias->Shape(), components), components}); + } + + if (mean != nullptr) { + program.AddOutputs({{mean, ProgramTensorMetadataDependency::None}}); } + if (inv_std_dev != nullptr) { + program.AddOutputs({{inv_std_dev, ProgramTensorMetadataDependency::None}}); + } + return context.RunProgram(program); } -ONNX_OPERATOR_KERNEL_EX( - LayerNormalization, - kOnnxDomain, - 17, - kWebGpuExecutionProvider, - (*KernelDefBuilder::Create()) - .TypeConstraint("T", WebGpuSupportedFloatTypes()), - LayerNorm); - -ONNX_OPERATOR_KERNEL_EX( - SimplifiedLayerNormalization, - kOnnxDomain, - 1, - kWebGpuExecutionProvider, - (*KernelDefBuilder::Create()).TypeConstraint("T", WebGpuSupportedFloatTypes()), - LayerNorm); +ONNX_OPERATOR_KERNEL_EX(LayerNormalization, kOnnxDomain, 17, kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()).TypeConstraint("T", WebGpuSupportedFloatTypes()), + LayerNorm); + +ONNX_OPERATOR_KERNEL_EX(SimplifiedLayerNormalization, kOnnxDomain, 1, kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T", WebGpuSupportedFloatTypes()) + .TypeConstraint("U", WebGpuSupportedFloatTypes()), + LayerNorm); } // namespace webgpu } // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/nn/layer_norm.h b/onnxruntime/core/providers/webgpu/nn/layer_norm.h index 17a9edbf4dd01..c7cb9280a0b77 100644 --- a/onnxruntime/core/providers/webgpu/nn/layer_norm.h +++ b/onnxruntime/core/providers/webgpu/nn/layer_norm.h @@ -11,25 +11,28 @@ namespace webgpu { class LayerNormProgram final : public Program { public: - LayerNormProgram(bool has_bias, - bool is_fp16, - bool simplified) : Program{"LayerNorm"}, - has_bias_{has_bias}, - is_fp16_{is_fp16}, - simplified_{simplified} {} + LayerNormProgram(bool has_bias, bool is_fp16, bool simplified, bool has_mean_output, + bool has_inv_std_dev_output) + : Program{"LayerNorm"}, + has_bias_{has_bias}, + is_fp16_{is_fp16}, + simplified_{simplified}, + has_mean_output_{has_mean_output}, + has_inv_std_dev_output_{has_inv_std_dev_output} {} Status GenerateShaderCode(ShaderHelper& sh) const override; - WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES( - {"norm_count", ProgramUniformVariableDataType::Uint32}, - {"norm_size", ProgramUniformVariableDataType::Uint32}, - {"norm_size_vectorized", ProgramUniformVariableDataType::Uint32}, - {"epsilon", ProgramUniformVariableDataType::Float32}); + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"norm_count", ProgramUniformVariableDataType::Uint32}, + {"norm_size", ProgramUniformVariableDataType::Uint32}, + {"norm_size_vectorized", ProgramUniformVariableDataType::Uint32}, + {"epsilon", ProgramUniformVariableDataType::Float32}); private: bool has_bias_; bool is_fp16_; bool simplified_; + bool has_mean_output_; + bool has_inv_std_dev_output_; }; template diff --git a/onnxruntime/core/providers/webgpu/nn/pool.cc b/onnxruntime/core/providers/webgpu/nn/pool.cc new file mode 100644 index 0000000000000..12c135dbbf46d --- /dev/null +++ b/onnxruntime/core/providers/webgpu/nn/pool.cc @@ -0,0 +1,252 @@ + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/string_macros.h" +#include "core/providers/webgpu/webgpu_supported_types.h" +#include "core/providers/webgpu/nn/pool.h" + +#include + +namespace onnxruntime { +namespace webgpu { + +namespace { + +std::vector NarrowToU32(const TensorShapeVector& shape) { + std::vector result; + result.reserve(shape.size()); + for (auto dim : shape) { + result.push_back(static_cast(dim)); + } + return result; +} + +} // namespace + +#define POOLING_KERNEL(op_name, domain, is_nhwc, pool_type, since_version) \ + ONNX_OPERATOR_KERNEL_EX(op_name, domain, since_version, kWebGpuExecutionProvider, \ + (*KernelDefBuilder::Create()).TypeConstraint("T", WebGpuSupportedFloatTypes()), \ + Pool); + +#define POOLING_KERNEL_VERSIONED(op_name, domain, is_nhwc, pool_type, since_version, end_version) \ + ONNX_OPERATOR_VERSIONED_KERNEL_EX(op_name, domain, since_version, end_version, kWebGpuExecutionProvider, \ + (*KernelDefBuilder::Create()).TypeConstraint("T", WebGpuSupportedFloatTypes()), \ + Pool); + +#define POOLING_KERNEL_WITH_INDICES(op_name, domain, is_nhwc, pool_type, since_version) \ + ONNX_OPERATOR_KERNEL_EX(op_name, domain, since_version, kWebGpuExecutionProvider, \ + (*KernelDefBuilder::Create()) \ + .TypeConstraint("T", WebGpuSupportedFloatTypes()) \ + .TypeConstraint("I", DataTypeImpl::GetTensorType()), \ + Pool); + +#define POOLING_KERNEL_VERSIONED_WITH_INDICES(op_name, domain, is_nhwc, pool_type, since_version, end_version) \ + ONNX_OPERATOR_VERSIONED_KERNEL_EX(op_name, domain, since_version, end_version, kWebGpuExecutionProvider, \ + (*KernelDefBuilder::Create()) \ + .TypeConstraint("T", WebGpuSupportedFloatTypes()) \ + .TypeConstraint("I", DataTypeImpl::GetTensorType()), \ + Pool); + +POOLING_KERNEL_VERSIONED(AveragePool, kOnnxDomain, false, AveragePool, 7, 9) +POOLING_KERNEL_VERSIONED(AveragePool, kMSInternalNHWCDomain, true, AveragePool, 7, 9) +POOLING_KERNEL_VERSIONED(AveragePool, kOnnxDomain, false, AveragePool, 10, 10) +POOLING_KERNEL_VERSIONED(AveragePool, kMSInternalNHWCDomain, true, AveragePool, 10, 10) +POOLING_KERNEL(AveragePool, kOnnxDomain, false, AveragePool, 11) +POOLING_KERNEL(AveragePool, kMSInternalNHWCDomain, true, AveragePool, 11) +POOLING_KERNEL(GlobalAveragePool, kOnnxDomain, false, AveragePool, 1) +POOLING_KERNEL(GlobalAveragePool, kMSInternalNHWCDomain, true, AveragePool, 1) + +POOLING_KERNEL_VERSIONED(MaxPool, kOnnxDomain, false, MaxPool<1>, 1, 7) +POOLING_KERNEL_VERSIONED(MaxPool, kMSInternalNHWCDomain, true, MaxPool<1>, 1, 7) +POOLING_KERNEL_VERSIONED_WITH_INDICES(MaxPool, kOnnxDomain, false, MaxPool<8>, 8, 9) +POOLING_KERNEL_VERSIONED_WITH_INDICES(MaxPool, kMSInternalNHWCDomain, true, MaxPool<8>, 8, 9) +POOLING_KERNEL_VERSIONED_WITH_INDICES(MaxPool, kOnnxDomain, false, MaxPool<8>, 10, 10) +POOLING_KERNEL_VERSIONED_WITH_INDICES(MaxPool, kMSInternalNHWCDomain, true, MaxPool<8>, 10, 10) +POOLING_KERNEL_VERSIONED_WITH_INDICES(MaxPool, kOnnxDomain, false, MaxPool<8>, 11, 11) +POOLING_KERNEL_VERSIONED_WITH_INDICES(MaxPool, kMSInternalNHWCDomain, true, MaxPool<8>, 11, 11) +POOLING_KERNEL_WITH_INDICES(MaxPool, kOnnxDomain, false, MaxPool<8>, 12) +POOLING_KERNEL_WITH_INDICES(MaxPool, kMSInternalNHWCDomain, true, MaxPool<8>, 12) +POOLING_KERNEL(GlobalMaxPool, kOnnxDomain, false, MaxPool<1>, 1) +POOLING_KERNEL(GlobalMaxPool, kMSInternalNHWCDomain, true, MaxPool<1>, 1) + +Status PoolProgram::GenerateShaderCode(ShaderHelper& shader) const { + const auto& input = shader.AddInput("input", ShaderUsage::UseUniform); + const auto& output = shader.AddOutput("output", ShaderUsage::UseUniform); + + // Declare and initialize the variables needed. + std::string var_decl_code; + // Process each element in the pooling window. + std::string sampling_code; + // Calculate the output value for each pooling window. + std::string downsampling_code; + + constexpr const size_t kStringInitialSize = 128; + if (is_max_pool_) { + std::string f16_min = "f16(-65504)"; + + SS(f32_min_ss, kStringInitialSize); + f32_min_ss << "f32(" << std::numeric_limits::lowest() << ")"; + std::string f32_min = SS_GET(f32_min_ss); + + SS(var_decl_ss, kStringInitialSize); + var_decl_ss << " var value = " << (is_float16_ ? f16_min : f32_min) << ";\n"; + var_decl_code = SS_GET(var_decl_ss); + + sampling_code = " value = max(value, x_val);\n"; + } else { + SS(var_decl_ss, kStringInitialSize); + var_decl_ss << " var value = " << (is_float16_ ? "f16(0)" : "f32(0)") << ";\n"; + if (!count_include_pad_) { + var_decl_ss << " var count = u32(0);\n"; + } else { + var_decl_ss << " var count = uniforms.kernel_size;\n"; + } + var_decl_code = SS_GET(var_decl_ss); + + SS(sampling_ss, kStringInitialSize); + sampling_ss << " value += x_val;\n"; + if (!count_include_pad_) { + sampling_ss << " count++;\n"; + } + sampling_code = SS_GET(sampling_ss); + + SS(downsampling_ss, kStringInitialSize); + downsampling_ss << " value /= " << (is_float16_ ? "f16" : "f32") << "(count);\n"; + downsampling_code = SS_GET(downsampling_ss); + } + + const auto kernel_rank = kernel_shape_.size(); + const auto pads_rank = kernel_shape_.size() * 2; + // The dimension index for H or D1 + const auto data_dim_begin = is_nhwc_ ? 1 : 2; + // The dimension index after W or Dn + auto data_dim_end = input.Rank(); + data_dim_end = is_nhwc_ ? data_dim_end - 1 : data_dim_end; + + auto& body = shader.MainFunctionBody(); + body << shader.GuardAgainstOutOfBoundsWorkgroupSizes("uniforms.output_size") + << " let y_indices = " << output.OffsetToIndices("global_idx") << ";\n" + << " var x_indices = y_indices;\n" + << " var k_indices: array;\n" + << var_decl_code + << " for (var i: u32 = 0; i < uniforms.kernel_size; i++) {\n" + << " var offset = i;\n" + // ---- Compute offset to indices in pooling window. + << " for (var j = 0; j < " << kernel_rank << "; j++) {\n" + << " k_indices[j] = offset / " << GetElementAt("uniforms.kernel_strides", "j", kernel_rank) << ";\n" + << " offset = offset % " << GetElementAt("uniforms.kernel_strides", "j", kernel_rank) << ";\n" + << " }\n" + // ---- Apply dilations in pooling window. + << " for (var j = 0; j < " << kernel_rank << "; j++) {\n" + << " k_indices[j] *= " << GetElementAt("uniforms.dilations", "j", kernel_rank) << ";\n" + << " }\n" + << " var is_pad = false;\n" + // ---- Compute x_indices in each data dimension + << " for (var j = " << data_dim_begin << "; j < " << data_dim_end << "; j++) {\n" + << " let d_idx = j - " << data_dim_begin << ";\n" + << " x_indices[j] = y_indices[j] * " << GetElementAt("uniforms.strides", "d_idx", kernel_rank) << ";\n" + << " x_indices[j] += k_indices[d_idx];\n" + << " x_indices[j] -= " << GetElementAt("uniforms.pads", "d_idx", pads_rank) << ";\n" + << " let j_dim_len = " << input.IndicesGet("uniforms.input_shape", "j") << ";\n" + // ------ Check if x_indices[j] is out of bounds to handle padding. + << " if (x_indices[j] < 0 || x_indices[j] >= j_dim_len) {\n" + << " is_pad = true;\n" + << " break;\n" + << " }\n" + << " }\n" + << " if (!is_pad) {\n" + << " let x_val = " << input.GetByIndices("x_indices") << ";\n" + << sampling_code + << " }\n" + << " }\n" + << downsampling_code + << " " << output.SetByOffset("global_idx", "value") << ";\n"; + + return Status::OK(); +} + +template +Status Pool::ComputeInternal(ComputeContext& context) const { + // TODO: support 'column major' storage_order. + ORT_RETURN_IF_NOT(pool_attrs_.storage_order == 0, "Using column major storage_order is not supported yet."); + + // TODO: support 'Indices' output. + ORT_RETURN_IF_NOT(context.OutputCount() == 1, "The Indices output is not supported yet."); + + const auto* X = context.Input(0); + const TensorShape& x_shape = X->Shape(); + const auto input_shape = x_shape.AsShapeVector(); + ORT_RETURN_IF_NOT(input_shape.size() >= 3, "Input dimension cannot be less than 3."); + + auto kernel_shape = pool_attrs_.kernel_shape; + auto strides = pool_attrs_.strides; + auto pads = pool_attrs_.pads; + auto dilations = pool_attrs_.dilations; + // Global pooling is equivalent to having the kernel size equal to the spatial dimension of input tensor. + if (pool_attrs_.global_pooling) { + if (!is_nhwc) { + kernel_shape.assign(input_shape.begin() + 2, input_shape.end()); + } else { + kernel_shape.assign(input_shape.begin() + 1, input_shape.end() - 1); + } + // No padding. + pads.assign(2 * kernel_shape.size(), 0); + // Stride of 1. + strides.assign(kernel_shape.size(), 1); + // Dilation of 1. + dilations.assign(kernel_shape.size(), 1); + } + + // Calculate the output shape + const auto out_channel = x_shape[is_nhwc ? input_shape.size() - 1 : 1]; + const auto output_shape = pool_attrs_.SetOutputSize(x_shape, out_channel, &pads, is_nhwc); + Tensor* Y = context.Output(0, output_shape); + + std::vector kernel_strides(kernel_shape.size()); + ORT_ENFORCE(kernel_shape.size() > 0, "kernel_shape must have at least one element."); + // Calculate the kernel element strides for each dimension in reverse order. For example: + // kernel_shape = [3, 2], kernel_strides = [2, 1] + // kernel_shape = [2, 3, 2], kernel_strides = [6, 2, 1] + for (size_t i = kernel_shape.size(); i > 0; --i) { + if (i == kernel_shape.size()) { + kernel_strides[i - 1] = 1; + } else { + kernel_strides[i - 1] = kernel_strides[i] * gsl::narrow_cast(kernel_shape[i]); + } + } + + bool is_max_pool = false; + if constexpr (PoolType::type == onnxruntime::PoolType::kMaxPool) { + is_max_pool = true; + } else if constexpr (PoolType::type != onnxruntime::PoolType::kAveragePool) { + ORT_NOT_IMPLEMENTED("Unsupported PoolType."); + } + bool is_float16 = X->GetElementType() == ONNX_NAMESPACE::TensorProto_DataType_FLOAT16; + bool count_include_pad = pool_attrs_.count_include_pad; + PoolProgram program{is_max_pool, is_nhwc, kernel_shape, is_float16, count_include_pad}; + + // Number of elements + uint32_t output_size = gsl::narrow_cast(Y->Shape().Size()); + uint32_t kernel_size = gsl::narrow_cast(TensorShape{kernel_shape}.Size()); + + const auto pads_u32 = NarrowToU32(pads); + const auto strides_u32 = NarrowToU32(strides); + const auto dilations_u32 = NarrowToU32(dilations); + + program.CacheHint(kernel_shape.size(), is_max_pool, is_nhwc, is_float16, count_include_pad) + .AddInputs({{X, ProgramTensorMetadataDependency::TypeAndRank}}) + .AddOutputs({{Y}}) + .SetDispatchGroupSize((output_size + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE) + .AddUniformVariables({output_size, kernel_size, + gsl::span(kernel_strides.data(), kernel_strides.size()), + gsl::span(pads_u32.data(), pads_u32.size()), + gsl::span(strides_u32.data(), strides_u32.size()), + gsl::span(dilations_u32.data(), dilations_u32.size())}); + + return context.RunProgram(program); +} + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/nn/pool.h b/onnxruntime/core/providers/webgpu/nn/pool.h new file mode 100644 index 0000000000000..c1716542e5549 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/nn/pool.h @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/webgpu/program.h" +#include "core/providers/webgpu/webgpu_kernel.h" +#include "core/providers/common.h" +#include "core/providers/cpu/nn/pool_base.h" + +namespace onnxruntime { +namespace webgpu { + +class PoolProgram final : public Program { + public: + PoolProgram(bool is_max_pool, bool is_nhwc, const TensorShapeVector& kernel_shape, bool is_float16, + bool count_include_pad) + : Program{"Pool"}, + is_max_pool_{is_max_pool}, + is_nhwc_{is_nhwc}, + kernel_shape_{kernel_shape}, + is_float16_{is_float16}, + count_include_pad_{count_include_pad} {} + + Status GenerateShaderCode(ShaderHelper& sh) const override; + + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"output_size", ProgramUniformVariableDataType::Uint32}, + {"kernel_size", ProgramUniformVariableDataType::Uint32}, + {"kernel_strides", ProgramUniformVariableDataType::Uint32}, + {"pads", ProgramUniformVariableDataType::Uint32}, + {"strides", ProgramUniformVariableDataType::Uint32}, + {"dilations", ProgramUniformVariableDataType::Uint32}); + + private: + // Whether it is max pool or average pool. + const bool is_max_pool_; + + const bool is_nhwc_; + const TensorShapeVector kernel_shape_; + const bool is_float16_; + const bool count_include_pad_; +}; + +template +class Pool : public WebGpuKernel, public PoolBase { + public: + explicit Pool(const OpKernelInfo& info) : WebGpuKernel(info), PoolBase(info) {} + + Status ComputeInternal(ComputeContext& context) const override; +}; + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/program.cc b/onnxruntime/core/providers/webgpu/program.cc index d1d4c242c4697..89f547481b6e4 100644 --- a/onnxruntime/core/providers/webgpu/program.cc +++ b/onnxruntime/core/providers/webgpu/program.cc @@ -102,6 +102,9 @@ constexpr std::string_view ProgramVariableDataTypeName[] = { "u8x4", // Uint8x4 "u8x8", // Uint8x8 "u8x16", // Uint8x16 + "i8x4", // Int8x4 + "i8x8", // Int8x8 + "i8x16", // Int8x16 }; std::ostream& operator<<(std::ostream& os, ProgramVariableDataType type) { os << ProgramVariableDataTypeName[std::underlying_type::type(type)]; @@ -129,6 +132,7 @@ int NumberOfComponents(ProgramVariableDataType type) { case ProgramVariableDataType::Float16x4: case ProgramVariableDataType::Boolx4: case ProgramVariableDataType::Uint8x4: + case ProgramVariableDataType::Int8x4: return 4; case ProgramVariableDataType::Uint8x8: return 8; @@ -142,6 +146,10 @@ int NumberOfComponents(ProgramVariableDataType type) { ProgramVariableDataType ToProgramVariableDataType(int32_t element_type, int component /* = 1 */) { if (component == 1) { switch (element_type) { + case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8: + return ProgramVariableDataType::Uint8x4; // shader needs to be aware that only 1 value is valid + case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8: + return ProgramVariableDataType::Int8x4; // shader needs to be aware that only 1 value is valid case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT: return ProgramVariableDataType::Float32; case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16: @@ -174,6 +182,8 @@ ProgramVariableDataType ToProgramVariableDataType(int32_t element_type, int comp switch (element_type) { case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8: return ProgramVariableDataType::Uint8x4; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8: + return ProgramVariableDataType::Int8x4; case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT: return ProgramVariableDataType::Float32x4; case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16: @@ -206,6 +216,26 @@ ProgramVariableDataType ToProgramVariableDataType(int32_t element_type, int comp } } +std::ostream& operator<<(std::ostream& os, ValidationMode mode) { + switch (mode) { + case ValidationMode::Disabled: + os << "Disabled"; + break; + case ValidationMode::WGPUOnly: + os << "WGPUOnly"; + break; + case ValidationMode::Basic: + os << "Basic"; + break; + case ValidationMode::Full: + os << "Full"; + break; + default: + os << "Unknown(" << static_cast(mode) << ")"; + } + return os; +} + namespace { TensorShape GetReducedShape(const TensorShape& shape, int component /* > 1 */) { ORT_ENFORCE(shape.NumDimensions() > 0 && shape.GetDims()[shape.NumDimensions() - 1] % component == 0, @@ -269,7 +299,7 @@ ProgramBase::ProgramBase(std::string_view name, ProgramMetadata&& metadata) } ProgramBase& ProgramBase::AddInput(ProgramInput&& input) { - inputs_.emplace_back(input); + inputs_.emplace_back(std::move(input)); return *this; } @@ -279,7 +309,7 @@ ProgramBase& ProgramBase::AddInputs(std::initializer_list inputs) } ProgramBase& ProgramBase::AddOutput(ProgramOutput&& output) { - outputs_.emplace_back(output); + outputs_.emplace_back(std::move(output)); return *this; } @@ -288,16 +318,6 @@ ProgramBase& ProgramBase::AddOutputs(std::initializer_list output return *this; } -ProgramBase& ProgramBase::AddIndices(const TensorShape& shape) { - indices_.emplace_back(shape); - return *this; -} - -ProgramBase& ProgramBase::AddIndices(TensorShape&& shape) { - indices_.emplace_back(shape); - return *this; -} - ProgramBase& ProgramBase::SetDispatchGroupSize(uint32_t x) { return SetDispatchGroupSize(x, 1, 1); } diff --git a/onnxruntime/core/providers/webgpu/program.h b/onnxruntime/core/providers/webgpu/program.h index 7bfd9e8800099..3b0acfa7d0d35 100644 --- a/onnxruntime/core/providers/webgpu/program.h +++ b/onnxruntime/core/providers/webgpu/program.h @@ -197,7 +197,10 @@ enum class ProgramVariableDataType { Boolx4, Uint8x4, Uint8x8, - Uint8x16 + Uint8x16, + Int8x4, + Int8x8, + Int8x16, }; #ifndef NDEBUG std::ostream& operator<<(std::ostream& os, ProgramVariableDataType); @@ -237,6 +240,7 @@ enum class ValidationMode { Basic, Full }; +std::ostream& operator<<(std::ostream& os, ValidationMode mode); namespace details { class ProgramWrapper; @@ -270,9 +274,11 @@ class ProgramBase { // add multiple program outputs ProgramBase& AddOutputs(std::initializer_list outputs); // add a program variable for indices - ProgramBase& AddIndices(const TensorShape& shape); - // add a program variable for indices - ProgramBase& AddIndices(TensorShape&& shape); + template + ProgramBase& AddIndices(Args&&... args) { + indices_.emplace_back(std::forward(args)...); + return *this; + } // set the size of dispatch groups. Y and Z are 1 if not specified. ProgramBase& SetDispatchGroupSize(uint32_t x); diff --git a/onnxruntime/core/providers/webgpu/program_manager.cc b/onnxruntime/core/providers/webgpu/program_manager.cc index 1fdd312d4f0d8..7a4a873a1adf3 100644 --- a/onnxruntime/core/providers/webgpu/program_manager.cc +++ b/onnxruntime/core/providers/webgpu/program_manager.cc @@ -24,14 +24,14 @@ Status ProgramManager::NormalizeDispatchGroupSize(uint32_t& x, uint32_t& y, uint auto limit_per_dimension = limits_.maxComputeWorkgroupsPerDimension; if (x > limit_per_dimension || y > limit_per_dimension || z > limit_per_dimension) { - auto size = static_cast(x) * static_cast(y) * static_cast(z); - uint32_t dispatch_avg = gsl::narrow(std::ceil(std::sqrt(size))); + double size = static_cast(x) * static_cast(y) * static_cast(z); + double dispatch_avg = std::ceil(std::sqrt(size)); if (dispatch_avg > limit_per_dimension) { - dispatch_avg = gsl::narrow(std::ceil(std::cbrt(size))); + dispatch_avg = std::ceil(std::cbrt(size)); ORT_RETURN_IF(dispatch_avg > limit_per_dimension, "The dispatch group size exceeds WebGPU maximum."); - x = y = z = dispatch_avg; + x = y = z = static_cast(dispatch_avg); } else { - x = y = dispatch_avg; + x = y = static_cast(dispatch_avg); z = 1; } } diff --git a/onnxruntime/core/providers/webgpu/program_manager.h b/onnxruntime/core/providers/webgpu/program_manager.h index 55721770014d2..feeb703b95aa2 100644 --- a/onnxruntime/core/providers/webgpu/program_manager.h +++ b/onnxruntime/core/providers/webgpu/program_manager.h @@ -6,7 +6,7 @@ #include #include -#include +#include "core/providers/webgpu/webgpu_external_header.h" #include "core/common/common.h" diff --git a/onnxruntime/core/providers/webgpu/quantization/quantize_linear.cc b/onnxruntime/core/providers/webgpu/quantization/quantize_linear.cc new file mode 100644 index 0000000000000..866b1debf6dc8 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/quantization/quantize_linear.cc @@ -0,0 +1,221 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include + +#include "core/util/math.h" +#include "core/providers/webgpu/quantization/quantize_linear.h" +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/webgpu_supported_types.h" +#include "core/providers/webgpu/webgpu_utils.h" + +namespace onnxruntime { +namespace webgpu { + +Status DequantizeLinearProgram::GenerateShaderCode(ShaderHelper& shader) const { + const auto& x = shader.AddInput("input", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseElementTypeAlias); + const auto& scale = shader.AddInput("scale", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseValueTypeAlias); + const auto& output = shader.AddOutput("output", ShaderUsage::UseUniform | ShaderUsage::UseShapeAndStride | ShaderUsage::UseValueTypeAlias); + + shader.MainFunctionBody() + << shader.GuardAgainstOutOfBoundsWorkgroupSizes("uniforms.output_size") + << "let output_indices = " << output.OffsetToIndices("global_idx") << ";\n"; + + // Get x input + if (packed_) { + std::string unpack = (signed_) ? "unpack4xI8(x)" : "unpack4xU8(x)"; + if (output.NumComponents() == 1) { + shader.MainFunctionBody() + << "let x = " << x.GetByOffset("global_idx / 4") << ";\n" + << "let x_vec = " << unpack << ";\n" + << "let x_value = x_vec[global_idx % 4];\n"; + } else { + shader.MainFunctionBody() + << "let x = " << x.GetByOffset("global_idx") << ";\n" + << "let x_vec = " << unpack << ";\n" + << "let x_value = x_vec;\n"; + } + } else { + shader.MainFunctionBody() + << "let x_value = " << x.GetByOffset("global_idx") << ";\n"; + } + + // Get scaler + if (per_layer_) { + // scale input is a scalar () + shader.MainFunctionBody() + << "let scale_value = " << scale.GetByOffset("0") << ";\n"; + } else if (per_axis_) { + shader.MainFunctionBody() + << "let scale_index = " << output.IndicesGet("output_indices", "uniforms.axis") << ";\n" + << "let scale_value = " << scale.GetByOffset("scale_index") << ";\n"; + } else { + // Block quantization. Scale input rank is same as input/output rank. + shader.MainFunctionBody() + << "var scale_indices: scale_indices_t = output_indices;\n" + << "let index = " << scale.IndicesGet("scale_indices", "uniforms.axis") << "/ uniforms.block_size;\n" + << scale.IndicesSet("scale_indices", "uniforms.axis", "index") << ";\n" + << "let scale_value = " << scale.GetByIndices("scale_indices") << ";\n"; + } + + // Get zero-point + if (has_zeropoint_) { + const auto& zero_point = shader.AddInput("zero_point", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias); + + std::string unpack = (signed_) ? "unpack4xI8(zero_point_input)" : "unpack4xU8(zero_point_input)"; + if (per_layer_) { + // zero-point input is a scalar + if (packed_) { + shader.MainFunctionBody() + << "let zero_point_input = " << zero_point.GetByOffset("0") << ";\n" + << "let zero_point_vec = " << unpack << ";\n" + << "let zero_point_value = zero_point_vec[0];\n"; + } else { + shader.MainFunctionBody() + << "let zero_point_value = " << zero_point.GetByOffset("0") << ";\n"; + } + } else if (per_axis_) { + // zero-point input is a 1D tensor + if (packed_) { + shader.MainFunctionBody() + << "let zero_point_index = " << output.IndicesGet("output_indices", "uniforms.axis") << ";\n" + << "let zero_point_input = " << zero_point.GetByOffset("zero_point_index / 4") << ";\n" + << "let zero_point_vec = " << unpack << ";\n" + << "let zero_point_value = zero_point_vec[zero_point_index % 4];\n"; + } else { + shader.MainFunctionBody() + << "let zero_point_index = " << output.IndicesGet("output_indices", "uniforms.axis") << ";\n" + << "let zero_point_value = " << zero_point.GetByOffset("zero_point_index") << ";\n"; + } + } else { + // BlockedQuantization. The zero-point input shape is same as the input shape except along axis. + if (packed_) { + shader.MainFunctionBody() + << "let zero_point_offset = " << scale.GetByIndices("scale_indices") << ";\n" + << "let zero_point_input = " << zero_point.GetByOffset("zero_point_offset / 4") << ";\n" + << "let zero_point_vec = " << unpack << ";\n" + << "let zero_point_value = zero_point_vec[zero_point_offset % 4];\n"; + } else { + shader.MainFunctionBody() + << "let zero_point_value = " << zero_point.GetByIndices("scale_indices") << ";\n"; + } + } + } else { + shader.MainFunctionBody() + << "let zero_point_value = input_element_t(0);\n"; + } + + // compute and write output + shader.MainFunctionBody() + << output.SetByOffset("global_idx", "(output_value_t(x_value) - scale_value_t(zero_point_value)) * scale_value"); + + return Status::OK(); +} + +Status DequantizeLinear::ComputeInternal(ComputeContext& context) const { + const auto* x = context.Input(0); + const auto* x_scale = context.Input(1); + const auto* x_zeropoint = context.Input(2); + const auto x_shape = x->Shape(); + int64_t x_size = x_shape.Size(); + auto* output_tensor = context.Output(0, x_shape); + int64_t x_scale_rank = x_scale->Shape().NumDimensions(); + + bool packed = x->GetElementType() == ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8 || x->GetElementType() == ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8; + bool is_signed = x->GetElementType() == ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8; + int64_t axis = (axis_ >= 0) ? axis_ : axis_ + x_shape.NumDimensions(); + + int max_components = GetMaxComponents(x_size); + if (max_components != 4) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "DequantizeLinear: components must be 4, but got ", max_components); + } + + // scaler - single scaler for all elements + bool per_layer = x_scale_rank == 0 || (x_scale_rank == 1 && x_scale->Shape()[0] == 1); + + // 1D tensor - 1 scaler for per axis + bool per_axis = per_layer == false && x_scale_rank == 1; + + bool use_components = per_layer && (!packed || max_components == 4); + int components = use_components ? max_components : 1; + int input_component = use_components && !packed ? max_components : 1; + + DequantizeLinearProgram program{packed, is_signed, per_layer, per_axis, x_zeropoint != nullptr}; + + program + .AddInputs({{x, ProgramTensorMetadataDependency::TypeAndRank, input_component}}) + .AddInputs({{x_scale, ProgramTensorMetadataDependency::TypeAndRank}}) + .AddOutput({output_tensor, ProgramTensorMetadataDependency::None, components}) + .SetDispatchGroupSize((x_size / components + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE) + .AddUniformVariables({{static_cast(axis)}}) + .AddUniformVariables({{static_cast(block_size_)}}) + .AddUniformVariables({{static_cast(x_size / components)}}) + .CacheHint(std::to_string(axis), std::to_string(is_signed), std::to_string(per_layer), std::to_string(per_axis), std::to_string(block_size_)); + + if (x_zeropoint != nullptr) { + program.AddInputs({{x_zeropoint, ProgramTensorMetadataDependency::TypeAndRank}}); + } + + return context.RunProgram(program); +} + +namespace { +const std::vector& DequantizeLinearConstraints() { + static std::vector types{ + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType()}; + return types; +} +} // namespace + +ONNX_OPERATOR_VERSIONED_KERNEL_EX( + DequantizeLinear, + kOnnxDomain, + 10, 12, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T", DequantizeLinearConstraints()), + DequantizeLinear); + +ONNX_OPERATOR_VERSIONED_KERNEL_EX( + DequantizeLinear, + kOnnxDomain, + 13, 18, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T", DequantizeLinearConstraints()), + DequantizeLinear); + +ONNX_OPERATOR_VERSIONED_KERNEL_EX( + DequantizeLinear, + kOnnxDomain, + 19, 20, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T1", DequantizeLinearConstraints()) + .TypeConstraint("T2", WebGpuSupportedFloatTypes()), + DequantizeLinear); + +ONNX_OPERATOR_VERSIONED_KERNEL_EX( + DequantizeLinear, + kOnnxDomain, + 21, 22, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T1", DequantizeLinearConstraints()) + .TypeConstraint("T2", WebGpuSupportedFloatTypes()), + DequantizeLinear); + +ONNX_OPERATOR_KERNEL_EX( + DequantizeLinear, + kOnnxDomain, + 23, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T1", DequantizeLinearConstraints()) + .TypeConstraint("T2", WebGpuSupportedFloatTypes()), + DequantizeLinear); + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/quantization/quantize_linear.h b/onnxruntime/core/providers/webgpu/quantization/quantize_linear.h new file mode 100644 index 0000000000000..95614998017e9 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/quantization/quantize_linear.h @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/webgpu/webgpu_kernel.h" + +namespace onnxruntime { +namespace webgpu { + +class DequantizeLinearProgram final : public Program { + public: + DequantizeLinearProgram(const bool packed, const bool issigned, const bool per_layer, + const bool per_axis, bool has_zeropoint) : Program{"DequantizeLinear"}, + packed_{packed}, + signed_{issigned}, + per_layer_{per_layer}, + per_axis_{per_axis}, + has_zeropoint_{has_zeropoint} {} + + Status GenerateShaderCode(ShaderHelper& sh) const override; + + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"axis", ProgramUniformVariableDataType::Uint32}, + {"block_size", ProgramUniformVariableDataType::Uint32}, + {"output_size", ProgramUniformVariableDataType::Uint32}); + + private: + bool packed_; + bool signed_; + bool per_layer_; + bool per_axis_; + bool has_zeropoint_; +}; + +class DequantizeLinear final : public WebGpuKernel { + public: + DequantizeLinear(const OpKernelInfo& info) : WebGpuKernel(info) { + axis_ = info.GetAttrOrDefault("axis", 1); + block_size_ = info.GetAttrOrDefault("block_size", 0); + output_dtype_ = info.GetAttrOrDefault("output_dtype", 0); + } + + Status ComputeInternal(ComputeContext& context) const override; + + private: + int64_t axis_; + int64_t block_size_; + int64_t output_dtype_; +}; + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/reduction/reduction_ops.cc b/onnxruntime/core/providers/webgpu/reduction/reduction_ops.cc new file mode 100644 index 0000000000000..8f2619b6cb2b6 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/reduction/reduction_ops.cc @@ -0,0 +1,379 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/webgpu/reduction/reduction_ops.h" +#include +#include "core/framework/data_transfer_manager.h" +#include "core/providers/webgpu/data_transfer.h" +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/webgpu_supported_types.h" + +namespace onnxruntime { +namespace webgpu { + +#define REGISTER_REDUCE_VERSIONED_KERNEL(ReduceOp, begin, end) \ + ONNX_OPERATOR_VERSIONED_KERNEL_EX( \ + ReduceOp, \ + kOnnxDomain, \ + begin, end, \ + kWebGpuExecutionProvider, \ + (*KernelDefBuilder::Create()).TypeConstraint("T", WebGpuSupportedNumberTypes()), \ + ReduceOp); + +#define REGISTER_REDUCE_VERSIONED_KERNEL_WITH_AXIS_IN_INPUT(ReduceOp, begin, end) \ + ONNX_OPERATOR_VERSIONED_KERNEL_EX( \ + ReduceOp, \ + kOnnxDomain, \ + begin, end, \ + kWebGpuExecutionProvider, \ + (*KernelDefBuilder::Create()).TypeConstraint("T", WebGpuSupportedNumberTypes()).InputMemoryType(OrtMemTypeCPUInput, 1), \ + ReduceOp); + +#define REGISTER_REDUCE_KERNEL(ReduceOp, version) \ + ONNX_OPERATOR_KERNEL_EX( \ + ReduceOp, \ + kOnnxDomain, \ + version, \ + kWebGpuExecutionProvider, \ + (*KernelDefBuilder::Create()).TypeConstraint("T", WebGpuSupportedNumberTypes()).InputMemoryType(OrtMemTypeCPUInput, 1), \ + ReduceOp); + +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceMean, 1, 10); +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceMean, 11, 12); +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceMean, 13, 17); +REGISTER_REDUCE_KERNEL(ReduceMean, 18); + +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceMax, 1, 10); +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceMax, 11, 11); +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceMax, 12, 12); +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceMax, 13, 17); +REGISTER_REDUCE_VERSIONED_KERNEL_WITH_AXIS_IN_INPUT(ReduceMax, 18, 19); +REGISTER_REDUCE_KERNEL(ReduceMax, 20); + +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceMin, 1, 10); +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceMin, 11, 11); +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceMin, 12, 12); +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceMin, 13, 17); +REGISTER_REDUCE_VERSIONED_KERNEL_WITH_AXIS_IN_INPUT(ReduceMin, 18, 19); +REGISTER_REDUCE_KERNEL(ReduceMin, 20); + +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceSum, 1, 10); +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceSum, 11, 12); +REGISTER_REDUCE_KERNEL(ReduceSum, 13); + +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceProd, 1, 10); +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceProd, 11, 12); +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceProd, 13, 17); +REGISTER_REDUCE_KERNEL(ReduceProd, 18); + +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceL1, 1, 10); +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceL1, 11, 12); +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceL1, 13, 17); +REGISTER_REDUCE_KERNEL(ReduceL1, 18); + +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceL2, 1, 10); +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceL2, 11, 12); +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceL2, 13, 17); +REGISTER_REDUCE_KERNEL(ReduceL2, 18); + +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceLogSum, 1, 10); +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceLogSum, 11, 12); +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceLogSum, 13, 17); +REGISTER_REDUCE_KERNEL(ReduceLogSum, 18); + +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceSumSquare, 1, 10); +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceSumSquare, 11, 12); +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceSumSquare, 13, 17); +REGISTER_REDUCE_KERNEL(ReduceSumSquare, 18); + +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceLogSumExp, 1, 10); +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceLogSumExp, 11, 12); +REGISTER_REDUCE_VERSIONED_KERNEL(ReduceLogSumExp, 13, 17); +REGISTER_REDUCE_KERNEL(ReduceLogSumExp, 18); + +REGISTER_REDUCE_VERSIONED_KERNEL(ArgMax, 1, 10); +REGISTER_REDUCE_VERSIONED_KERNEL(ArgMax, 11, 12); +REGISTER_REDUCE_KERNEL(ArgMax, 13); + +REGISTER_REDUCE_VERSIONED_KERNEL(ArgMin, 1, 10); +REGISTER_REDUCE_VERSIONED_KERNEL(ArgMin, 11, 12); +REGISTER_REDUCE_KERNEL(ArgMin, 13); + +Status ReduceKernelProgram::GenerateShaderCode(ShaderHelper& shader) const { + const auto& output = shader.AddOutput("output", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseValueTypeAlias); + if (is_input_empty_) { + shader.MainFunctionBody() << shader.GuardAgainstOutOfBoundsWorkgroupSizes("uniforms.output_size") + << code_[0] + << code_[2] + << output.SetByOffset("global_idx", "output_value"); + return Status::OK(); + } + const auto& input = shader.AddInput("input", ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseValueTypeAlias); + bool reduce_on_all_axes = no_op_with_empty_axes_ == false && axes_.empty(); + std::string loop_header = code_[0].find("first_element") == std::string::npos ? code_[0] : "let first_element = " + input.GetByIndices("input_indices") + ";\n" + code_[0] + "\n"; + std::string loop_body = "let current_element: input_value_t = " + input.GetByIndices("input_indices") + ";\n" + code_[1]; + std::string loop_footer = code_[2]; + const auto input_rank = input.Rank(); + for (int i = 0, l = 0; i < input_rank; ++i) { + if (reduce_on_all_axes || std::find(axes_.begin(), axes_.end(), i) != axes_.end()) { + if (keepdims_) { + l++; + } + std::stringstream ss; + std::string index = "i" + std::to_string(i); + ss << "for (var " << index << " : u32 = 0; " << index << " < " << input.IndicesGet("uniforms.input_shape", i) << "; " << index << "++) {\n"; + if (loop_body.find("last_index") != std::string::npos) { + ss << "let last_index = " + index + ";\n"; + } + ss << input.IndicesSet("input_indices", i, index) << ";\n"; + ss << loop_body << "\n"; + ss << "}\n"; + loop_body = ss.str(); + } else { + std::stringstream ss; + std::string index = "i" + std::to_string(i); + ss << "let " << index << " = " << output.IndicesGet("output_indices", l) << ";\n"; + ss << input.IndicesSet("input_indices", i, index) << ";\n"; + ss << loop_header << "\n"; + loop_header = ss.str(); + l++; + } + } + std::stringstream input_indices_init_value; + for (int i = 0; i < input_rank - 1; ++i) { + input_indices_init_value << "0, "; + } + input_indices_init_value << "0"; + shader.MainFunctionBody() << shader.GuardAgainstOutOfBoundsWorkgroupSizes("uniforms.output_size") + << "let output_indices: output_indices_t = " << output.OffsetToIndices("global_idx") << ";\n" + << "var input_indices: input_indices_t = input_indices_t(" << input_indices_init_value.str() << ");\n" + << loop_header << loop_body << loop_footer; + shader.MainFunctionBody() << output.SetByOffset("global_idx", "output_value"); + return Status::OK(); +} + +template +Status ReduceKernel::ComputeInternal(ComputeContext& context) const { + const auto* input_tensor = context.Input(0); + ORT_RETURN_IF_ERROR(CheckInput(input_tensor)); + InlinedVector input_axes; + auto rank = input_tensor->Shape().NumDimensions(); + auto transform_axis = [rank](int64_t axis) { + if (axis < 0) { + axis += rank; + } + if (axis < 0 || static_cast(axis) >= rank) { + ORT_THROW("Axes values must be in the range [-rank, rank-1]. Got: ", axis); + } + return static_cast(axis); + }; + // Check if axes input is provided and copy the axes values to input_axes + if (context.InputCount() > 1) { + ORT_ENFORCE(axes_.empty(), "Axes attribute may not be specified when axes input is also provided."); + const Tensor* axes_tensor = context.Input(1); + if (nullptr != axes_tensor) { + auto size = static_cast(axes_tensor->Shape()[0]); + const auto* data = axes_tensor->Data(); + input_axes.reserve(size); + std::transform(data, data + size, std::back_inserter(input_axes), transform_axis); + } + } else { + input_axes.reserve(axes_.size()); + std::transform(axes_.begin(), axes_.end(), std::back_inserter(input_axes), transform_axis); + } + if (input_axes.empty()) { + if (noop_with_empty_axes_ || rank == 0) { + // If axes is empty and noop_with_empty_axes_ is true, it is a no-op according to the spec + // If input tensor is a scalar and it's not a ReduceLogSum or ReduceSumSquare, return the input tensor as is. + if (rank == 0 && (name_ == "ReduceLogSum" || name_ == "ReduceSumSquare" || name_ == "ReduceL1" || name_ == "ReduceL2")) { + // For ReduceLogSum with scalar input, output = log(input) + // For ReduceSumSquare with scalar input, output = input * input + auto output = context.Output(0, input_tensor->Shape()); + // We need to run the operation even for scalar inputs for these ops + const auto code = GetOpSpecificCode(input_tensor); + constexpr uint32_t output_size = 1; + constexpr uint32_t reduce_axes = 0; + ReduceKernelProgram program(name_, keepdims_, noop_with_empty_axes_, input_axes, code, false); + program.AddInput({input_tensor, ProgramTensorMetadataDependency::TypeAndRank}) + .AddOutput({output, ProgramTensorMetadataDependency::TypeAndRank}) + .SetDispatchGroupSize(1) + .AddUniformVariables({{output_size}, {static_cast(noop_with_empty_axes_ ? 1 : 0)}, {reduce_axes}}); + return context.RunProgram(program); + } else { + // For other ops, or when axes is empty with noop_with_empty_axes_ true, just copy the input + auto output = context.Output(0, input_tensor->Shape()); + if (output->DataRaw() != input_tensor->DataRaw()) { + ORT_RETURN_IF_ERROR(Info().GetDataTransferManager().CopyTensor(*input_tensor, *output)); + } + return Status::OK(); + } + } else { + // If axes is empty and noop_with_empty_axes_ is false, it is a reduction over all axes + input_axes.resize(rank); + std::iota(input_axes.begin(), input_axes.end(), 0); + } + } + const auto code = GetOpSpecificCode(input_tensor); + // Compute output shape + std::vector output_shape; + bool is_input_empty = false; + for (size_t i = 0; i < input_tensor->Shape().NumDimensions(); ++i) { + is_input_empty |= input_tensor->Shape()[i] == 0; + if (std::find(input_axes.begin(), input_axes.end(), i) != input_axes.end()) { + if (keepdims_) { + output_shape.push_back(1); + } + } else { + output_shape.push_back(input_tensor->Shape()[i]); + } + } + TensorShape output_tensor_shape(output_shape); + int64_t output_size = output_tensor_shape.Size(); + if (output_size == 0) { + ORT_IGNORE_RETURN_VALUE(context.Output(0, output_tensor_shape)); + return Status::OK(); + } + + auto input_rank = input_tensor->Shape().NumDimensions(); + // reduce_axes element is either 1 or 0 depending on whether the axis is reduced or not + std::vector reduce_axes; + reduce_axes.resize(input_rank, 0); + for (auto axis : input_axes) { + reduce_axes[axis] = 1; + } + + ReduceKernelProgram program(name_, keepdims_, noop_with_empty_axes_, input_axes, code, is_input_empty); + if (!is_input_empty) { + program.AddInput({input_tensor, ProgramTensorMetadataDependency::TypeAndRank}); + } + + // TODO: the ReduceKernel class is designed to use `keepdims_`, `noop_with_empty_axes_` and input axes as uniform variables, + // but the current implementation does not work without them in cache key. + // This is a temporary workaround to make it work. We should fix this in the future. + program.CacheHint(keepdims_, + noop_with_empty_axes_, + select_last_index_, + absl::StrJoin(input_axes, ",")) + .AddOutput({context.Output(0, output_shape), ProgramTensorMetadataDependency::TypeAndRank}) + .SetDispatchGroupSize((output_size + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE) + .AddUniformVariables({{static_cast(output_size)}, + {static_cast(noop_with_empty_axes_ ? 1 : 0)}, + {reduce_axes}}); + + return context.RunProgram(program); +} + +ReduceOpSpecificCode ReduceMean::GetOpSpecificCode(const Tensor* input_tensor) const { + const TensorShape& input_shape = input_tensor->Shape(); + size_t input_rank = input_shape.NumDimensions(); + std::string loop_header = "var sum = f32(0);"; + std::string loop_body = "sum += f32(current_element);"; + std::stringstream ss; + ss << "var size: u32 = 1;\n" + << "for (var i: u32 = 0; i < " << input_rank << "; i += 1) { \n" + << " let index_reduced_or_not = " << GetElementAt("uniforms.reduce_axes", "i", input_rank) << ";\n" + << " if (index_reduced_or_not == 1) { \n" + << " size = size * " << GetElementAt("uniforms.input_shape", "i", input_rank) << ";\n" + << " }\n" + << "}\n" + << "let output_value = output_value_t(sum / f32(size));"; + std::string loop_footer = ss.str(); + ReduceOpSpecificCode code({loop_header, loop_body, loop_footer}); + return code; +} + +ReduceOpSpecificCode ReduceMax::GetOpSpecificCode(const Tensor* input_tensor) const { + ORT_UNUSED_PARAMETER(input_tensor); + std::string loop_header = "var max_element = first_element;"; + std::string loop_body = "max_element = max(max_element, current_element);"; + std::string loop_footer = "let output_value = output_value_t(max_element);"; + ReduceOpSpecificCode code({loop_header, loop_body, loop_footer}); + return code; +} +ReduceOpSpecificCode ReduceMin::GetOpSpecificCode(const Tensor* input_tensor) const { + ORT_UNUSED_PARAMETER(input_tensor); + std::string loop_header = "var min_element = first_element;"; + std::string loop_body = "min_element = min(min_element, current_element);"; + std::string loop_footer = "let output_value = output_value_t(min_element);"; + ReduceOpSpecificCode code({loop_header, loop_body, loop_footer}); + return code; +} +ReduceOpSpecificCode ReduceSum::GetOpSpecificCode(const Tensor* input_tensor) const { + ORT_UNUSED_PARAMETER(input_tensor); + std::string loop_header = "var sum = f32(0);"; + std::string loop_body = "sum += f32(current_element);"; + std::string loop_footer = "let output_value = output_value_t(sum);"; + ReduceOpSpecificCode code({loop_header, loop_body, loop_footer}); + return code; +} +ReduceOpSpecificCode ReduceProd::GetOpSpecificCode(const Tensor* input_tensor) const { + ORT_UNUSED_PARAMETER(input_tensor); + std::string loop_header = "var prod = f32(1);"; + std::string loop_body = "prod *= f32(current_element);"; + std::string loop_footer = "let output_value = output_value_t(prod);"; + ReduceOpSpecificCode code({loop_header, loop_body, loop_footer}); + return code; +} +ReduceOpSpecificCode ReduceL1::GetOpSpecificCode(const Tensor* input_tensor) const { + ORT_UNUSED_PARAMETER(input_tensor); + std::string loop_header = "var l1 = f32(0);"; + std::string loop_body = "l1 += abs(f32(current_element));"; + std::string loop_footer = "let output_value = output_value_t(l1);"; + ReduceOpSpecificCode code({loop_header, loop_body, loop_footer}); + return code; +} +ReduceOpSpecificCode ReduceL2::GetOpSpecificCode(const Tensor* input_tensor) const { + ORT_UNUSED_PARAMETER(input_tensor); + std::string loop_header = "var l2 = f32(0);"; + std::string loop_body = "let t = f32(current_element); l2 += (t * t);"; + std::string loop_footer = "l2 = sqrt(l2); let output_value = output_value_t(l2);"; + ReduceOpSpecificCode code({loop_header, loop_body, loop_footer}); + return code; +} +ReduceOpSpecificCode ReduceLogSum::GetOpSpecificCode(const Tensor* input_tensor) const { + ORT_UNUSED_PARAMETER(input_tensor); + std::string loop_header = "var sum = f32(0);"; + std::string loop_body = "sum += f32(current_element);"; + std::string loop_footer = "let log_sum = log(sum); let output_value = output_value_t(log_sum);"; + ReduceOpSpecificCode code({loop_header, loop_body, loop_footer}); + return code; +} +ReduceOpSpecificCode ReduceSumSquare::GetOpSpecificCode(const Tensor* input_tensor) const { + ORT_UNUSED_PARAMETER(input_tensor); + std::string loop_header = "var sum_square = f32(0);"; + std::string loop_body = "let t = f32(current_element); sum_square += (t * t);"; + std::string loop_footer = "let output_value = output_value_t(sum_square);"; + ReduceOpSpecificCode code({loop_header, loop_body, loop_footer}); + return code; +} +ReduceOpSpecificCode ReduceLogSumExp::GetOpSpecificCode(const Tensor* input_tensor) const { + ORT_UNUSED_PARAMETER(input_tensor); + std::string loop_header = "var sum_exp = f32(0);"; + std::string loop_body = "sum_exp += exp(f32(current_element));"; + std::string loop_footer = "let log_sum_exp = log(sum_exp); let output_value = output_value_t(log_sum_exp);"; + ReduceOpSpecificCode code({loop_header, loop_body, loop_footer}); + return code; +} + +ReduceOpSpecificCode ArgMin::GetOpSpecificCode(const Tensor* input_tensor) const { + ORT_UNUSED_PARAMETER(input_tensor); + std::string op = (select_last_index_) ? "<=" : "<"; + std::string loop_header = "var best_element = first_element; var best_index = u32(0);"; + std::string loop_body = "if (current_element " + op + " best_element) { best_element = current_element; best_index = last_index; };"; + std::string loop_footer = "let output_value = output_value_t(best_index);"; + ReduceOpSpecificCode code({loop_header, loop_body, loop_footer}); + return code; +} + +ReduceOpSpecificCode ArgMax::GetOpSpecificCode(const Tensor* input_tensor) const { + ORT_UNUSED_PARAMETER(input_tensor); + std::string op = (select_last_index_) ? ">=" : ">"; + std::string loop_header = "var best_element = first_element; var best_index = u32(0);"; + std::string loop_body = "if (current_element " + op + " best_element) { best_element = current_element; best_index = last_index; };"; + std::string loop_footer = "let output_value = output_value_t(best_index);"; + ReduceOpSpecificCode code({loop_header, loop_body, loop_footer}); + return code; +} + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/reduction/reduction_ops.h b/onnxruntime/core/providers/webgpu/reduction/reduction_ops.h new file mode 100644 index 0000000000000..70ae6d3c71eb9 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/reduction/reduction_ops.h @@ -0,0 +1,135 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include "core/common/optional.h" +#include "core/providers/webgpu/webgpu_supported_types.h" +#include "core/providers/webgpu/webgpu_kernel.h" +#include "core/providers/cpu/reduction/reduction_kernel_base.h" +#include "core/providers/webgpu/program.h" +#include "core/providers/webgpu/shader_helper.h" +namespace onnxruntime { +namespace webgpu { +// reduceOpSpecificCode is a 3-element array of strings that represent the op specific code for the reduce operation. +// The first element is the loop header, the second element is the loop body, and the third element is the loop footer. +// The loop header is the code that is executed before the loop starts. The loop body is the code that is executed for each element in the loop. +// The loop footer is the code that is executed after the loop ends. The loop body should contain the code that accumulates the result of the reduction and +// the loop footer should contain the code that assigins output_value the result of the reduction. +typedef std::array ReduceOpSpecificCode; +class ReduceKernelProgram final : public Program { + public: + ReduceKernelProgram(std::string name, bool keepdims, bool no_op_with_empty_axes, const InlinedVector& axes, ReduceOpSpecificCode code, bool is_input_empty) : Program{name}, keepdims_(keepdims), no_op_with_empty_axes_(no_op_with_empty_axes), axes_(axes.begin(), axes.end()), code_(code), is_input_empty_(is_input_empty) {} + Status GenerateShaderCode(ShaderHelper& wgpuShaderModuleAddRef) const override; + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"output_size", ProgramUniformVariableDataType::Uint32}, + {"no_op_with_empty_axes", ProgramUniformVariableDataType::Uint32}, + {"reduce_axes", ProgramUniformVariableDataType::Uint32}); + + private: + const bool keepdims_; + const bool no_op_with_empty_axes_; + InlinedVector axes_; + ReduceOpSpecificCode code_; + bool is_input_empty_; +}; + +template +class ReduceKernel : public WebGpuKernel, public ReduceKernelBase { + protected: + using ReduceKernelBase::axes_; + using ReduceKernelBase::noop_with_empty_axes_; + using ReduceKernelBase::keepdims_; + using ReduceKernelBase::select_last_index_; + + ReduceKernel(const OpKernelInfo& info, std::string name, bool allow_empty_input = false, optional keepdims_override = {}) + : WebGpuKernel(info), + ReduceKernelBase(info, keepdims_override), + name_(name), + allow_empty_input_(allow_empty_input) { + } + Status ComputeInternal(ComputeContext& ctx) const; + virtual ReduceOpSpecificCode GetOpSpecificCode(const Tensor* input_tensor) const = 0; + + Status CheckInput(const Tensor* input_tensor) const { + ORT_ENFORCE(input_tensor != nullptr && (input_tensor->Shape().Size() > 0 || allow_empty_input_), "Input tensor cannot be null or empty"); + return Status::OK(); + } + + private: + std::string name_; + bool allow_empty_input_; +}; + +class ReduceMean final : public ReduceKernel { + public: + ReduceMean(const OpKernelInfo& info) : ReduceKernel(info, "ReduceMean", true) {} + ReduceOpSpecificCode GetOpSpecificCode(const Tensor* input_tensor) const override; +}; + +class ReduceMax final : public ReduceKernel { + public: + ReduceMax(const OpKernelInfo& info) : ReduceKernel(info, "ReduceMax") {} + ReduceOpSpecificCode GetOpSpecificCode(const Tensor* input_tensor) const override; +}; + +class ReduceMin final : public ReduceKernel { + public: + ReduceMin(const OpKernelInfo& info) : ReduceKernel(info, "ReduceMin") {} + ReduceOpSpecificCode GetOpSpecificCode(const Tensor* input_tensor) const override; +}; + +class ReduceSum final : public ReduceKernel { + public: + ReduceSum(const OpKernelInfo& info) : ReduceKernel(info, "ReduceSum", true) {} + ReduceOpSpecificCode GetOpSpecificCode(const Tensor* input_tensor) const override; +}; + +class ReduceProd final : public ReduceKernel { + public: + ReduceProd(const OpKernelInfo& info) : ReduceKernel(info, "ReduceProd", true) {} + ReduceOpSpecificCode GetOpSpecificCode(const Tensor* input_tensor) const override; +}; + +class ReduceL1 final : public ReduceKernel { + public: + ReduceL1(const OpKernelInfo& info) : ReduceKernel(info, "ReduceL1", true) {} + ReduceOpSpecificCode GetOpSpecificCode(const Tensor* input_tensor) const override; +}; + +class ReduceL2 final : public ReduceKernel { + public: + ReduceL2(const OpKernelInfo& info) : ReduceKernel(info, "ReduceL2", true) {} + ReduceOpSpecificCode GetOpSpecificCode(const Tensor* input_tensor) const override; +}; + +class ReduceLogSum final : public ReduceKernel { + public: + ReduceLogSum(const OpKernelInfo& info) : ReduceKernel(info, "ReduceLogSum", true) {} + ReduceOpSpecificCode GetOpSpecificCode(const Tensor* input_tensor) const override; +}; + +class ReduceSumSquare final : public ReduceKernel { + public: + ReduceSumSquare(const OpKernelInfo& info) : ReduceKernel(info, "ReduceSumSquare", true) {} + ReduceOpSpecificCode GetOpSpecificCode(const Tensor* input_tensor) const override; +}; + +class ReduceLogSumExp final : public ReduceKernel { + public: + ReduceLogSumExp(const OpKernelInfo& info) : ReduceKernel(info, "ReduceLogSumExp", true) {} + ReduceOpSpecificCode GetOpSpecificCode(const Tensor* input_tensor) const override; +}; + +class ArgMin final : public ReduceKernel { + public: + ArgMin(const OpKernelInfo& info) : ReduceKernel(info, "ArgMin", true) {} + ReduceOpSpecificCode GetOpSpecificCode(const Tensor* input_tensor) const override; +}; + +class ArgMax final : public ReduceKernel { + public: + ArgMax(const OpKernelInfo& info) : ReduceKernel(info, "ArgMax", true) {} + ReduceOpSpecificCode GetOpSpecificCode(const Tensor* input_tensor) const override; +}; + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/shader_helper.cc b/onnxruntime/core/providers/webgpu/shader_helper.cc index 305bbd2bd20b0..bac360c4c270e 100644 --- a/onnxruntime/core/providers/webgpu/shader_helper.cc +++ b/onnxruntime/core/providers/webgpu/shader_helper.cc @@ -65,8 +65,8 @@ Status ShaderHelper::Init() { " @builtin(local_invocation_id) local_id : vec3"; if (device_.HasFeature(wgpu::FeatureName::Subgroups)) { body_ss_ << ",\n" - " @builtin(subgroup_invocation_id) sg_id : u32,\n" - " @builtin(subgroup_size) sg_size : u32"; + " @builtin(subgroup_invocation_id) sg_id : u32,\n" + " @builtin(subgroup_size) sg_size : u32"; } if (!is_1d_dispatch) { body_ss_ << ",\n" @@ -104,12 +104,19 @@ const ShaderVariableHelper& ShaderHelper::AddOutput(const std::string& name, Sha return AddVariableImpl(false, name, usage, dims); } -const ShaderIndicesHelper& ShaderHelper::AddIndices(const std::string& name, bool use_uniform) { +const ShaderIndicesHelper& ShaderHelper::AddIndices(const std::string& name, ShaderUsage usage) { const size_t indices_index = indices_vars_.size(); + ORT_ENFORCE(indices_index < program_.Indices().size(), + "Too many indices in the program (", program_.Indices().size(), ")"); + + // usage of indices should not use flag other than UseUniform and UseIndicesTypeAlias + ORT_ENFORCE(!(usage & ~(ShaderUsage::UseUniform | ShaderUsage::UseIndicesTypeAlias)), + "Invalid usage for indices variable ", name); + return *indices_vars_.emplace_back( std::make_unique(name, ProgramVariableDataType::InvalidType, - use_uniform ? ShaderUsage::UseUniform : ShaderUsage::None, + usage, program_.Indices()[indices_index])); } @@ -161,6 +168,12 @@ Status ValidateVariableDataType(int32_t element_type, ProgramVariableDataType va var_type == ProgramVariableDataType::Uint8x16, "Unexpected program variable type ", int(var_type), " for uint8 tensor"); break; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8: + ORT_RETURN_IF_NOT(var_type == ProgramVariableDataType::Int8x4 || + var_type == ProgramVariableDataType::Int8x8 || + var_type == ProgramVariableDataType::Int8x16, + "Unexpected program variable type ", int(var_type), " for int8 tensor"); + break; default: ORT_RETURN_IF(true, "Unsupported data type: ", element_type); // todo: add int4/uint4 @@ -345,9 +358,6 @@ Status ShaderHelper::GenerateSourceCode(std::string& code, std::vector& sha })) { ORT_RETURN_IF_NOT(device_.HasFeature(wgpu::FeatureName::ShaderF16), "Program ", program_.Name(), " requires f16 but the device does not support it."); ss << "enable f16;\n"; - if (device_.HasFeature(wgpu::FeatureName::SubgroupsF16)) { - ss << "enable subgroups_f16;\n"; - } } if (device_.HasFeature(wgpu::FeatureName::Subgroups)) { ss << "enable subgroups;\n"; diff --git a/onnxruntime/core/providers/webgpu/shader_helper.h b/onnxruntime/core/providers/webgpu/shader_helper.h index dac08f3bd9368..e5f316a46bedc 100644 --- a/onnxruntime/core/providers/webgpu/shader_helper.h +++ b/onnxruntime/core/providers/webgpu/shader_helper.h @@ -5,7 +5,7 @@ #include -#include +#include "core/providers/webgpu/webgpu_external_header.h" #include "core/framework/tensor_shape.h" @@ -86,7 +86,7 @@ class ShaderHelper final { ShaderUsage usage = ShaderUsage::UseIndicesTypeAlias | ShaderUsage::UseValueTypeAlias | ShaderUsage::UseUniform); // Add an indices variable to the shader. - const ShaderIndicesHelper& AddIndices(const std::string& name, bool use_uniform = true); + const ShaderIndicesHelper& AddIndices(const std::string& name, ShaderUsage usage = ShaderUsage::UseUniform); // Get the string stream for additional implementation code to the shader. inline OStringStream& AdditionalImplementation() { diff --git a/onnxruntime/core/providers/webgpu/shader_variable.cc b/onnxruntime/core/providers/webgpu/shader_variable.cc index 5e5920f582251..502d03c2c2dd8 100644 --- a/onnxruntime/core/providers/webgpu/shader_variable.cc +++ b/onnxruntime/core/providers/webgpu/shader_variable.cc @@ -32,6 +32,7 @@ constexpr static const std::string_view STORAGE_TYPE_ARRAY[] = { "u32", // Uint8x4 "vec2", // Uint8x8 "vec4", // Uint8x16 + "u32", // Int8x4 }; constexpr static const auto STORAGE_TYPE = details::_to_std_array(STORAGE_TYPE_ARRAY); @@ -54,6 +55,7 @@ constexpr static const std::string_view VALUE_TYPE_ARRAY[] = { "u32", // Uint8x4 (u32 as 4 elements of uint8) "vec2", // Uint8x8 (vec2 as 2x4 elements of uint8) "vec4", // Uint8x16 (vec4 as 4x4 elements of uint8) + "i32", // Int8x4 }; constexpr static const auto VALUE_TYPE = details::_to_std_array(VALUE_TYPE_ARRAY); @@ -76,6 +78,9 @@ constexpr static const std::string_view ELEMENT_TYPE_ARRAY[] = { "u32", // Uint8x4 "u32", // Uint8x8 "u32", // Uint8x16 + "i32", // Int8x4 + "i32", // Int8x8 + "i32", // Int8x16 }; constexpr static const auto ELEMENT_TYPE = details::_to_std_array(ELEMENT_TYPE_ARRAY); @@ -91,7 +96,7 @@ ShaderIndicesHelper::ShaderIndicesHelper(std::string_view name, ProgramVariableD : name_(name), type_(type), num_components_{NumberOfComponents(type)}, - rank_{gsl::narrow(dims.NumDimensions())}, + rank_{static_cast(dims.NumDimensions())}, dims_{dims}, usage_(usage), indices_type_{GetIndicesType(rank_)}, diff --git a/onnxruntime/core/providers/webgpu/tensor/cast.cc b/onnxruntime/core/providers/webgpu/tensor/cast.cc index 8b5bede34e6d0..7f92ea4ed3776 100644 --- a/onnxruntime/core/providers/webgpu/tensor/cast.cc +++ b/onnxruntime/core/providers/webgpu/tensor/cast.cc @@ -69,7 +69,7 @@ Status Cast::ComputeInternal(ComputeContext& context) const { if (size == 0) { return Status::OK(); } - uint32_t vec_size = gsl::narrow((size + 3) / 4); + uint32_t vec_size = onnxruntime::narrow((size + 3) / 4); CastProgram program{to_}; program diff --git a/onnxruntime/core/providers/webgpu/tensor/cast.h b/onnxruntime/core/providers/webgpu/tensor/cast.h index ef5c4d5d0dabe..925cd200f0aba 100644 --- a/onnxruntime/core/providers/webgpu/tensor/cast.h +++ b/onnxruntime/core/providers/webgpu/tensor/cast.h @@ -26,7 +26,7 @@ class Cast final : public WebGpuKernel { int64_t to; Status status = info.GetAttr("to", &to); ORT_ENFORCE(status.IsOK(), "Attribute to is not set."); - to_ = gsl::narrow(to); + to_ = onnxruntime::narrow(to); // ignore attribute 'saturate' as float8 is not supported in WebGPU } diff --git a/onnxruntime/core/providers/webgpu/tensor/concat.cc b/onnxruntime/core/providers/webgpu/tensor/concat.cc index 5ed8099fde05e..5cfd6c78f8929 100644 --- a/onnxruntime/core/providers/webgpu/tensor/concat.cc +++ b/onnxruntime/core/providers/webgpu/tensor/concat.cc @@ -104,7 +104,7 @@ Status Concat::ComputeInternal(ComputeContext& context) const { return Status::OK(); } - uint32_t output_size = gsl::narrow_cast(prepare.output_tensor->Shape().Size()); + uint32_t output_size = onnxruntime::narrow(prepare.output_tensor->Shape().Size()); size_t axis = static_cast(prepare.axis); ConcatProgram program{axis}; diff --git a/onnxruntime/core/providers/webgpu/tensor/expand.cc b/onnxruntime/core/providers/webgpu/tensor/expand.cc index 809616660aa9e..3e831f9853451 100644 --- a/onnxruntime/core/providers/webgpu/tensor/expand.cc +++ b/onnxruntime/core/providers/webgpu/tensor/expand.cc @@ -42,7 +42,7 @@ Status Expand::ComputeInternal(ComputeContext& context) const { : 1; const int components_o = output_shape.IsScalar() ? 1 : output_shape[output_shape.NumDimensions() - 1] % 4 == 0 ? 4 : 1; - uint32_t data_size = gsl::narrow(output_shape.Size() / components_o); + uint32_t data_size = onnxruntime::narrow(output_shape.Size() / components_o); ExpandProgram program{}; program @@ -53,7 +53,7 @@ Status Expand::ComputeInternal(ComputeContext& context) const { {data_size}, }); if (components_i != components_o) { - program.AddIndices(output_shape); + program.AddIndices(std::move(output_shape)); } return context.RunProgram(program); } diff --git a/onnxruntime/core/providers/webgpu/tensor/gather.cc b/onnxruntime/core/providers/webgpu/tensor/gather.cc index 9f6e5f2420d86..39d07991f3c5a 100644 --- a/onnxruntime/core/providers/webgpu/tensor/gather.cc +++ b/onnxruntime/core/providers/webgpu/tensor/gather.cc @@ -42,7 +42,7 @@ Status GatherProgram::GenerateShaderCode(ShaderHelper& shader) const { Status Gather::ComputeInternal(ComputeContext& context) const { Prepare p; ORT_RETURN_IF_ERROR(PrepareForCompute(&context.KernelContext(), p)); - uint32_t data_size = gsl::narrow(p.output_tensor->Shape().Size()); + uint32_t data_size = onnxruntime::narrow(p.output_tensor->Shape().Size()); if (data_size == 0) { return Status::OK(); } diff --git a/onnxruntime/core/providers/webgpu/tensor/pad.cc b/onnxruntime/core/providers/webgpu/tensor/pad.cc new file mode 100644 index 0000000000000..5adf873be7897 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/tensor/pad.cc @@ -0,0 +1,265 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include +#include + +#include "core/util/math.h" +#include "core/providers/webgpu/string_macros.h" +#include "core/providers/webgpu/tensor/pad.h" +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/webgpu_supported_types.h" + +namespace onnxruntime { +namespace webgpu { + +Status PadProgram::GenerateShaderCode(ShaderHelper& shader) const { + if (!dim_value_zero_) { + shader.AddInput("data", ShaderUsage::UseUniform | ShaderUsage::UseShapeAndStride); + } + const auto& output = shader.AddOutput("output", ShaderUsage::UseUniform | ShaderUsage::UseShapeAndStride | ShaderUsage::UseValueTypeAlias); + + shader.MainFunctionBody() << shader.GuardAgainstOutOfBoundsWorkgroupSizes("uniforms.output_size"); + std::string constant_value_str = std::string("let constant_value = ") + + (is_float16_ ? "bitcast>(uniforms.constant_value)[0];\n" : "bitcast(uniforms.constant_value);\n"); + if (dim_value_zero_) { + // Only Constant mode needs fill output if the one dim value or mores dims' values of input are zero. + shader.MainFunctionBody() << constant_value_str + << "output[global_idx] = constant_value;\n"; + return Status::OK(); + } + + shader.MainFunctionBody() << " let output_indices = " << output.OffsetToIndices("global_idx") << ";\n" + << " var input_index = u32(0);\n" + << " var use_pad_value = false;\n" + << " var in_coord = i32(0);\n"; + + const int rank = output.Rank(); + std::string output_indices_str = "i32(" + GetElementAt("output_indices", "dim", rank) + ")"; + std::string lower_pads_str = GetElementAt("uniforms.lower_pads", "dim", rank); + std::string data_shape_str = "i32(" + GetElementAt("uniforms.data_shape", "dim", rank) + ")"; + std::string data_stride_str = rank == 1 ? "" : " * " + GetElementAt("uniforms.data_stride", "dim", rank - 1); + SS(axis_body_ss, 1024); + switch (mode_) { + case Mode::Constant: + axis_body_ss << " if (" << output_indices_str << " < " << lower_pads_str << " || " << output_indices_str << " >= " << lower_pads_str << " + " << data_shape_str << ") {\n" + << " use_pad_value = true;\n"; + break; + case Mode::Edge: + axis_body_ss << " if (" << output_indices_str << " < " << lower_pads_str << ") {\n" + << " in_coord = 0;\n" + << " } else if (" << output_indices_str << " >= " << lower_pads_str << " + " << data_shape_str << ") {\n" + << " in_coord = " << data_shape_str + " - 1;\n"; + break; + case Mode::Reflect: + axis_body_ss << " if (" << output_indices_str << " < " << lower_pads_str << " || " << output_indices_str << " >= " << lower_pads_str << " + " << data_shape_str << ") {\n" + << " in_coord = " << output_indices_str << " - " << lower_pads_str << ";\n" + << " if (in_coord < 0) {\n" + << " in_coord = -in_coord;\n" + << " }\n" + << " {\n" + << " let _2n_1 = 2 * (" << data_shape_str << " - 1);\n" + << " in_coord = in_coord % _2n_1;\n" + << " if(in_coord >= " << data_shape_str << ") {\n" + << " in_coord = _2n_1 - in_coord;\n" + << " }\n" + << " }\n"; + break; + case Mode::Wrap: + axis_body_ss << " if (" << output_indices_str << " < " << lower_pads_str << ") {\n" + << " in_coord = " << data_shape_str << " + " << output_indices_str << " - " << lower_pads_str + ";\n" + << " } else if (" << output_indices_str << " >= " << lower_pads_str << " + " << data_shape_str << ") {\n" + << " in_coord = " << output_indices_str << " - " << lower_pads_str << " - " << data_shape_str << ";\n"; + break; + default: + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Unsupported mode type: ", static_cast(mode_)); + } + axis_body_ss << " } else {\n" + << " " << "in_coord = " << output_indices_str << " - " << lower_pads_str << ";\n" + << " }\n"; + + shader.MainFunctionBody() << " for (var dim = 0; dim < " << rank << " && !use_pad_value; dim++) {\n" + << SS_GET(axis_body_ss) + << " input_index += select(u32(in_coord)" << data_stride_str << ", u32(in_coord), dim == " << rank - 1 << ");\n" + << " }\n" + << " " << constant_value_str + << " " << output.SetByOffset("global_idx", "select(data[input_index], constant_value, use_pad_value)"); + + return Status::OK(); +} + +Status Pad::ComputeInternal(ComputeContext& context) const { + const Tensor* input_tensor = context.Input(0); + auto const& input_shape = input_tensor->Shape(); + size_t dimension_count = input_shape.NumDimensions(); + + const PadsVector* p_pads = &pads_; + const PadsVector* p_slices = &slices_; + + PadsVector pads; + PadsVector slices; + // kOnnxDomain Pad opset >= 11 (Or) kMsDomain opset == 1 + if (is_dynamic_) { + size_t data_rank = input_tensor->Shape().NumDimensions(); + + const Tensor* pads_tensor = context.Input(1); + auto pads_tensor_dims = pads_tensor->Shape().GetDims(); + ORT_ENFORCE(pads_tensor_dims.size() == 1 || (pads_tensor_dims.size() == 2 && pads_tensor_dims[0] == 1), + "Pads tensor should be a 1D tensor of shape [2 * num_axes] " + "or a 2D tensor of shape [1, 2 * num_axes]"); + + const auto pads_data = pads_tensor->DataAsSpan(); + + // Compute Pads by applying axes if specified otherwise copy the supplied pads. + PadBase::ComputePads(context.KernelContext(), data_rank, pads_data, pads); + + // Separate out any negative pads into the slices array + PadBase::SeparateNegativeToSlices(pads, slices); + + p_pads = &pads; + p_slices = &slices; + } + + auto output_dims(input_shape.AsShapeVector()); + ORT_ENFORCE(dimension_count * 2 == p_pads->size(), "'pads' attribute has wrong number of values"); + + // Calculate output dimensions, and handle any negative padding + std::vector lower_pads(dimension_count); + for (size_t i = 0; i < dimension_count; i++) { + int64_t lower_pad = (*p_pads)[i] + (*p_slices)[i]; + int64_t upper_pad = (*p_pads)[i + dimension_count] + (*p_slices)[i + dimension_count]; + lower_pads[i] = static_cast(lower_pad); + output_dims[i] += lower_pad + upper_pad; + } + TensorShape output_shape(output_dims); + + // special case when there is a dim value of 0 in the shape. behavior depends on mode + bool dim_value_zero = input_shape.Size() == 0; + if (dim_value_zero) { + ORT_RETURN_IF_ERROR(PadBase::HandleDimValueZero(mode_, input_shape, output_shape)); + } + + auto* output_tensor = context.Output(0, output_shape); + uint32_t output_size = onnxruntime::narrow(output_shape.Size()); + if (output_size == 0) { + // Do not need to fill output, return + return Status::OK(); + } + + // Read constant value and bitcast to uint32. + uint32_t value_uint32 = 0; + const auto data_type = input_tensor->GetElementType(); + bool is_float16 = data_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT16; + const Tensor* value_tensor = context.Input(2); + if (!is_dynamic_) { + if (is_float16) { + uint16_t value = math::floatToHalf(value_); + std::memcpy(&value_uint32, &value, sizeof(value)); + } else { + std::memcpy(&value_uint32, &value_, sizeof(value_uint32)); + } + } else if (value_tensor) { + ORT_ENFORCE(value_tensor->DataType() == input_tensor->DataType() && value_tensor->Shape().Size() == 1, + "Value tensor should be a 1D tensor of size 1 with the same type as that of the input tensor"); + switch (data_type) { + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT16: { + uint16_t value = value_tensor->Data()[0].val; + std::memcpy(&value_uint32, &value, sizeof(value)); + } break; + case ONNX_NAMESPACE::TensorProto_DataType_INT32: + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: + case ONNX_NAMESPACE::TensorProto_DataType_UINT32: + std::memcpy(&value_uint32, value_tensor->DataRaw(), sizeof(value_uint32)); + break; + default: + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Unsupported input type: ", static_cast(data_type)); + } + } + + PadProgram program{mode_, dim_value_zero, is_float16}; + if (!dim_value_zero) { + program.AddInput({input_tensor, ProgramTensorMetadataDependency::Rank}); + } + program.AddOutput({output_tensor, ProgramTensorMetadataDependency::TypeAndRank}) + .SetDispatchGroupSize((output_size + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE) + .CacheHint(std::to_string(static_cast(mode_)), dim_value_zero) + .AddUniformVariables({{gsl::span(lower_pads.data(), lower_pads.size())}, {output_size}, {value_uint32}}); + + return context.RunProgram(program); +} + +ONNX_OPERATOR_VERSIONED_KERNEL_EX( + Pad, + kOnnxDomain, + 2, 10, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T", WebGpuSupportedNumberTypes()), + Pad); +ONNX_OPERATOR_VERSIONED_KERNEL_EX( + Pad, + kOnnxDomain, + 11, 12, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .InputMemoryType(OrtMemTypeCPUInput, 1) + .InputMemoryType(OrtMemTypeCPUInput, 2) + .TypeConstraint("T", WebGpuSupportedNumberTypes()), + Pad); +ONNX_OPERATOR_VERSIONED_KERNEL_EX( + Pad, + kOnnxDomain, + 13, 17, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .InputMemoryType(OrtMemTypeCPUInput, 1) + .InputMemoryType(OrtMemTypeCPUInput, 2) + .TypeConstraint("T", WebGpuSupportedNumberTypes()), + Pad); +ONNX_OPERATOR_VERSIONED_KERNEL_EX( + Pad, + kOnnxDomain, + 18, 18, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .InputMemoryType(OrtMemTypeCPUInput, 1) + .InputMemoryType(OrtMemTypeCPUInput, 2) + .InputMemoryType(OrtMemTypeCPUInput, 3) + .TypeConstraint("T", WebGpuSupportedNumberTypes()), + Pad); +ONNX_OPERATOR_VERSIONED_KERNEL_EX( + Pad, + kOnnxDomain, + 19, 20, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .InputMemoryType(OrtMemTypeCPUInput, 1) + .InputMemoryType(OrtMemTypeCPUInput, 2) + .InputMemoryType(OrtMemTypeCPUInput, 3) + .TypeConstraint("T", WebGpuSupportedNumberTypes()), + Pad); +ONNX_OPERATOR_VERSIONED_KERNEL_EX( + Pad, + kOnnxDomain, + 21, 22, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .InputMemoryType(OrtMemTypeCPUInput, 1) + .InputMemoryType(OrtMemTypeCPUInput, 2) + .InputMemoryType(OrtMemTypeCPUInput, 3) + .TypeConstraint("T", WebGpuSupportedNumberTypes()), + Pad); +ONNX_OPERATOR_KERNEL_EX( + Pad, + kOnnxDomain, + 23, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .InputMemoryType(OrtMemTypeCPUInput, 1) + .InputMemoryType(OrtMemTypeCPUInput, 2) + .InputMemoryType(OrtMemTypeCPUInput, 3) + .TypeConstraint("T", WebGpuSupportedNumberTypes()), + Pad); + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/tensor/pad.h b/onnxruntime/core/providers/webgpu/tensor/pad.h new file mode 100644 index 0000000000000..58049ddb0e5ce --- /dev/null +++ b/onnxruntime/core/providers/webgpu/tensor/pad.h @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/webgpu/program.h" +#include "core/providers/webgpu/webgpu_kernel.h" +#include "core/providers/cpu/tensor/padbase.h" + +namespace onnxruntime { +namespace webgpu { + +class PadProgram final : public Program { + public: + PadProgram(const Mode mode, bool dim_value_zero, bool is_float16) : Program{"Pad"}, + mode_{mode}, + dim_value_zero_{dim_value_zero}, + is_float16_{is_float16} {} + + Status GenerateShaderCode(ShaderHelper& sh) const override; + + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"lower_pads", ProgramUniformVariableDataType::Int32}, + {"output_size", ProgramUniformVariableDataType::Uint32}, + {"constant_value", ProgramUniformVariableDataType::Uint32}); + + private: + Mode mode_; + bool dim_value_zero_; + bool is_float16_; +}; + +class Pad final : public PadBase, public WebGpuKernel { + public: + Pad(const OpKernelInfo& info) : PadBase(info), WebGpuKernel(info) {} + + Status ComputeInternal(ComputeContext& context) const override; +}; + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/tensor/resize.cc b/onnxruntime/core/providers/webgpu/tensor/resize.cc new file mode 100644 index 0000000000000..daacced0df871 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/tensor/resize.cc @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/webgpu/tensor/resize.h" +#include "core/providers/webgpu/webgpu_supported_types.h" + +namespace onnxruntime { +namespace webgpu { + +ONNX_OPERATOR_VERSIONED_KERNEL_EX( + Resize, + kOnnxDomain, + 10, 10, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .InputMemoryType(OrtMemTypeCPUInput, 1) + .TypeConstraint("T", WebGpuSupportedNumberTypes()), + Resize); + +ONNX_OPERATOR_VERSIONED_KERNEL_EX( + Resize, + kOnnxDomain, + 11, 12, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .InputMemoryType(OrtMemTypeCPUInput, 1) + .InputMemoryType(OrtMemTypeCPUInput, 2) + .InputMemoryType(OrtMemTypeCPUInput, 3) + .TypeConstraint("T1", WebGpuSupportedNumberTypes()), + Resize); + +ONNX_OPERATOR_VERSIONED_KERNEL_EX( + Resize, + kOnnxDomain, + 13, 17, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .InputMemoryType(OrtMemTypeCPUInput, 1) + .InputMemoryType(OrtMemTypeCPUInput, 2) + .InputMemoryType(OrtMemTypeCPUInput, 3) + .TypeConstraint("T1", WebGpuSupportedNumberTypes()), + Resize); + +ONNX_OPERATOR_VERSIONED_KERNEL_EX( + Resize, + kOnnxDomain, + 18, 18, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .InputMemoryType(OrtMemTypeCPUInput, 1) + .InputMemoryType(OrtMemTypeCPUInput, 2) + .InputMemoryType(OrtMemTypeCPUInput, 3) + .TypeConstraint("T1", WebGpuSupportedNumberTypes()), + Resize); + +ONNX_OPERATOR_KERNEL_EX( + Resize, + kOnnxDomain, + 19, + kWebGpuExecutionProvider, + (*KernelDefBuilder::Create()) + .InputMemoryType(OrtMemTypeCPUInput, 1) + .InputMemoryType(OrtMemTypeCPUInput, 2) + .InputMemoryType(OrtMemTypeCPUInput, 3) + .TypeConstraint("T1", WebGpuSupportedNumberTypes()), + Resize); + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/tensor/resize.h b/onnxruntime/core/providers/webgpu/tensor/resize.h new file mode 100644 index 0000000000000..a37d784bcf8fd --- /dev/null +++ b/onnxruntime/core/providers/webgpu/tensor/resize.h @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/webgpu/webgpu_kernel.h" +#include "core/providers/webgpu/program.h" +#include "core/providers/webgpu/tensor/upsample.h" + +namespace onnxruntime { +namespace webgpu { + +class Resize : public Upsample { + public: + Resize(const OpKernelInfo& info) : Upsample(info) { + } + + Status ComputeInternal(ComputeContext& context) const override { + return Upsample::ComputeInternal(context); + } +}; + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/tensor/resize_impl.cc b/onnxruntime/core/providers/webgpu/tensor/resize_impl.cc new file mode 100644 index 0000000000000..75a7f859c965f --- /dev/null +++ b/onnxruntime/core/providers/webgpu/tensor/resize_impl.cc @@ -0,0 +1,603 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/common/inlined_containers.h" +#include "core/providers/webgpu/tensor/resize_impl.h" +#include "core/providers/cpu/tensor/utils.h" +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/webgpu_supported_types.h" + +namespace onnxruntime { +namespace webgpu { + +std::string GetSafeIntegerDivision(ResizeCoordinateTransformationMode transform_coordinate) { + // The whole part and the fractional part are calculated separately due to inaccuracy of floating + // point division. As an example, f32(21) / f32(7) may evaluate to 2.99... instead of 3, causing an + // offset-by-one error later in floor(). + switch (transform_coordinate) { + case ResizeCoordinateTransformationMode::ASYMMETRIC: + return std::string("select(f32(x_resized * length_original / length_resized) + ") + + "f32(x_resized * length_original % length_resized) / f32(length_resized), " + + "f32(x_resized) / x_scale, x_scale < 1.0 || floor(x_scale) != x_scale)"; + break; + case ResizeCoordinateTransformationMode::ALIGN_CORNERS: + return std::string("select(f32(x_resized * (length_original - 1) / (length_resized - 1)) + ") + + "f32(x_resized * (length_original - 1) % (length_resized - 1)) / f32(length_resized - 1), " + + "0.0, length_resized == 1)"; + break; + default: + ORT_THROW("The transform coordinate mode does not need to use SafeIntegerDivision"); + } +} + +void TransformCoordinate(std::ostream& os, ResizeCoordinateTransformationMode transform_coordinate) { + std::string params; + std::string body; + switch (transform_coordinate) { + case ResizeCoordinateTransformationMode::HALF_PIXEL: + params = "x_resized: u32, x_scale: f32"; + body = "(f32(x_resized) + 0.5) / x_scale - 0.5"; + break; + case ResizeCoordinateTransformationMode::ASYMMETRIC: + params = "x_resized: u32, x_scale: f32, length_resized: u32, length_original: u32"; + body = GetSafeIntegerDivision(transform_coordinate); + break; + case ResizeCoordinateTransformationMode::PYTORCH_HALF_PIXEL: + params = "x_resized: u32, x_scale: f32, length_resized: u32"; + body = "select(0.0, (f32(x_resized) + 0.5) / x_scale - 0.5, length_resized > 1)"; + break; + case ResizeCoordinateTransformationMode::TF_HALF_PIXEL_FOR_NN: + params = "x_resized: u32, x_scale: f32"; + body = "(f32(x_resized) + 0.5) / x_scale"; + break; + case ResizeCoordinateTransformationMode::ALIGN_CORNERS: + params = "x_resized: u32, length_resized: u32, length_original: u32"; + body = GetSafeIntegerDivision(transform_coordinate); + break; + case ResizeCoordinateTransformationMode::TF_CROP_AND_RESIZE: + params = "x_resized: u32, length_resized: u32, length_original: u32, roi_start: f32, roi_end: f32"; + body = std::string("select(0.5 * (roi_start + roi_end) * f32(length_original - 1),") + + "roi_start * f32(length_original - 1) + (f32(x_resized) * (roi_end - roi_start) * " + + "f32(length_original - 1)) / f32(length_resized - 1), length_resized > 1)"; + break; + case ResizeCoordinateTransformationMode::HALF_PIXEL_SYMMETRIC: + params = "x_resized: u32, x_scale: f32, length_resized: u32, length_original: u32"; + body = std::string("(f32(length_original) / 2.0) * (1.0 - f32(length_resized) / ") + + "(x_scale * f32(length_original))) + (f32(x_resized) + 0.5) / x_scale - 0.5"; + break; + default: + ORT_THROW("unknown ResizeCoordinateTransformationMode"); + } + + os << "fn transform_coordinate(" << params << ") -> f32 {\n"; + os << "return " << body << ";\n}\n"; +} + +std::string GetCoordinateCaller(ResizeCoordinateTransformationMode transform_coordinate, int32_t rank) { + std::string scales_index_str = GetElementAt("uniforms.scales", "axis", rank); + std::string input_shape_index_str = GetElementAt("uniforms.input_shape", "axis", rank); + std::string output_shape_index_str = GetElementAt("uniforms.output_shape", "axis", rank); + std::string roi_start_str = GetElementAt("uniforms.roi", "axis", rank * 2); + std::string roi_end_str = GetElementAt("uniforms.roi", "axis + " + std::to_string(rank), rank * 2); + std::stringstream caller_ss; + caller_ss << "transform_coordinate(output_coord, "; + switch (transform_coordinate) { + case ResizeCoordinateTransformationMode::HALF_PIXEL: + case ResizeCoordinateTransformationMode::TF_HALF_PIXEL_FOR_NN: + caller_ss << scales_index_str; + break; + case ResizeCoordinateTransformationMode::ASYMMETRIC: + caller_ss << scales_index_str << ", " << output_shape_index_str << ", " << input_shape_index_str; + break; + case ResizeCoordinateTransformationMode::PYTORCH_HALF_PIXEL: + caller_ss << scales_index_str << ", " << output_shape_index_str; + break; + case ResizeCoordinateTransformationMode::ALIGN_CORNERS: + caller_ss << output_shape_index_str << ", " << input_shape_index_str; + break; + case ResizeCoordinateTransformationMode::TF_CROP_AND_RESIZE: + caller_ss << output_shape_index_str << ", " << input_shape_index_str + << ", f32(" << roi_start_str << "), f32(" << roi_end_str << ")"; + break; + case ResizeCoordinateTransformationMode::HALF_PIXEL_SYMMETRIC: + caller_ss << scales_index_str << ", " << output_shape_index_str << ", " << input_shape_index_str; + break; + default: + ORT_THROW("unknown ResizeCoordinateTransformationMode"); + } + caller_ss << ")"; + + return caller_ss.str(); +} + +void CalcNearestPixel(std::ostream& os, ResizeNearestMode mode) { + std::string params = "x_original: f32"; + std::string body; + switch (mode) { + case ResizeNearestMode::SIMPLE: + params += ", is_down_sampling: bool"; + body = "select(i32(x_original), i32(ceil(x_original)), is_down_sampling)"; + break; + case ResizeNearestMode::ROUND_PREFER_FLOOR: + body = "select(i32(round(x_original)), i32(floor(x_original)), x_original == f32(i32(x_original)) + 0.5)"; + break; + case ResizeNearestMode::ROUND_PREFER_CEIL: + body = "select(i32(round(x_original)), i32(ceil(x_original)), x_original == f32(i32(x_original)) + 0.5)"; + break; + case ResizeNearestMode::FLOOR: + body = "i32(floor(x_original))"; + break; + case ResizeNearestMode::CEIL: + body = "i32(ceil(x_original))"; + break; + default: + ORT_THROW("unknown ResizeNearestMode"); + } + + os << "fn calc_nearest_pixel(" << params << ") -> i32 {\n"; + os << "return " << body << ";\n}\n"; +} + +std::string GetNearestPixelCaller(ResizeNearestMode mode) { + switch (mode) { + case ResizeNearestMode::SIMPLE: + return "calc_nearest_pixel(input_coord, uniforms.scales[axis] < 1.0)"; + break; + case ResizeNearestMode::ROUND_PREFER_FLOOR: + case ResizeNearestMode::ROUND_PREFER_CEIL: + case ResizeNearestMode::FLOOR: + case ResizeNearestMode::CEIL: + return "calc_nearest_pixel(input_coord)"; + break; + default: + ORT_THROW("unknown ResizeNearestMode"); + } +} + +Status ResizeNearestProgram::GenerateShaderCode(ShaderHelper& shader) const { + const ShaderVariableHelper& input = shader.AddInput("input", ShaderUsage::UseUniform | + ShaderUsage::UseShapeAndStride | + ShaderUsage::UseValueTypeAlias); + const ShaderVariableHelper& output = shader.AddOutput("output", ShaderUsage::UseUniform | + ShaderUsage::UseShapeAndStride); + + std::string scales_index_str = GetElementAt("uniforms.scales", "axis", rank_); + std::string input_shape_index_str = GetElementAt("uniforms.input_shape", "axis", rank_); + std::string input_stride_index_str = GetElementAt("uniforms.input_stride", "axis", rank_ - 1); + + std::stringstream extrapolation_ss; + if (extrapolation_enabled_) { + extrapolation_ss << " if ((input_coord < 0.0 || input_coord > f32(" << input_shape_index_str << " - 1))) {\n" + << " " << output.SetByOffset("global_idx", "input_value_t(uniforms.extrapolation_value)") << ";\n" + << " return;\n" + << " }\n"; + } + + TransformCoordinate(shader.AdditionalImplementation(), coordinate_transform_mode_); + CalcNearestPixel(shader.AdditionalImplementation(), nearest_mode_); + shader.MainFunctionBody() << shader.GuardAgainstOutOfBoundsWorkgroupSizes("uniforms.output_size") + << " let output_indices = " << output.OffsetToIndices("global_idx") << ";\n" + << " var input_index = u32(0);\n" + << " for(var axis = 0; axis < " << rank_ << "; axis++) {\n" + << " var output_coord = output_indices[axis];\n" + << " if (" << scales_index_str << " != 1.0) {\n" + << " let input_coord = " << GetCoordinateCaller(coordinate_transform_mode_, rank_) << ";\n" + << extrapolation_ss.str() + << " var nearest_coord = " << GetNearestPixelCaller(nearest_mode_) << ";\n" + << " if (nearest_coord >= i32(" << input_shape_index_str << ")) {\n" + << " output_coord = " << input_shape_index_str << " - 1;\n" + << " } else if (nearest_coord < 0) {\n" + << " output_coord = 0;\n" + << " } else {\n" + << " output_coord = u32(nearest_coord);\n" + << " }" + << " }\n" + << " input_index += select(output_coord * " << input_stride_index_str << ", output_coord, axis == " << rank_ - 1 << ");\n" + << " }\n" + << " " << output.SetByOffset("global_idx", input.GetByOffset("input_index")) << ";\n"; + + return Status::OK(); +} + +Status ResizeNearestImpl(ComputeContext& context, + const Tensor* input_tensor, + int32_t rank, + gsl::span& output_dims, + gsl::span roi, + gsl::span scales, + bool extrapolation_enabled, + const float extrapolation_value, + onnxruntime::ResizeCoordinateTransformationMode coordinate_transform_mode, + onnxruntime::ResizeNearestMode nearest_mode) { + TensorShape output_shape(output_dims); + auto* output_tensor = context.Output(0, output_shape); + uint32_t output_size = onnxruntime::narrow(output_shape.Size()); + + ResizeNearestProgram program{coordinate_transform_mode, nearest_mode, extrapolation_enabled, rank}; + program.AddInput({input_tensor, ProgramTensorMetadataDependency::TypeAndRank}) + .AddOutput({output_tensor, ProgramTensorMetadataDependency::Rank}) + .SetDispatchGroupSize((output_size + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE) + .CacheHint(std::to_string(static_cast(extrapolation_enabled)), + std::to_string(static_cast(coordinate_transform_mode)), + std::to_string(static_cast(nearest_mode))) + .AddUniformVariables({{roi}, {scales}, {output_size}, {extrapolation_value}}); + + return context.RunProgram(program); +} + +Status ResizeBilinearProgram::GenerateShaderCode(ShaderHelper& shader) const { + const ShaderVariableHelper& input = shader.AddInput("input", ShaderUsage::UseUniform | + ShaderUsage::UseShapeAndStride | + ShaderUsage::UseValueTypeAlias); + const ShaderVariableHelper& output = shader.AddOutput("output", ShaderUsage::UseUniform | + ShaderUsage::UseShapeAndStride); + + std::string scales_index_str = GetElementAt("uniforms.scales", "axis", rank_); + std::string input_shape_index_str = GetElementAt("uniforms.input_shape", "axis", rank_); + + std::stringstream extrapolation_ss; + if (extrapolation_enabled_) { + extrapolation_ss << " if ((input_coord < 0.0 || input_coord > input_max_coord)) {\n" + << " " << output.SetByOffset("global_idx", "input_value_t(uniforms.extrapolation_value)") << ";\n" + << " return;\n" + << " }\n"; + } + + TransformCoordinate(shader.AdditionalImplementation(), coordinate_transform_mode_); + std::string transform_coordinate_caller = GetCoordinateCaller(coordinate_transform_mode_, rank_); + shader.MainFunctionBody() << shader.GuardAgainstOutOfBoundsWorkgroupSizes("uniforms.output_size") + << " let output_indices = " << output.OffsetToIndices("global_idx") << ";\n" + << " var input_indices = " << output.OffsetToIndices("global_idx") << ";\n" + << " var axis = " << rank_ - 2 << ";\n" + << " let input_height = u32(" << input_shape_index_str << ");\n" + << " var input_max_coord = f32(input_height - 1);\n" + << " var output_coord = output_indices[axis];\n" + << " var input_coord = select(f32(output_coord), " << transform_coordinate_caller << " , " << scales_index_str << " != 1.0);\n" + << extrapolation_ss.str() + << " input_coord = max(0.0, min(input_coord, input_max_coord));\n" + << " let input_y_coord_int = u32(input_coord);\n" + << " let y_weight_0 = select(input_coord - f32(input_y_coord_int), 0.5, input_coord >= input_max_coord);\n" + << " axis = " << rank_ - 1 << ";\n" + << " let input_width = u32(" << input_shape_index_str << ");\n" + << " input_max_coord = f32(input_width - 1);\n" + << " output_coord = output_indices[axis];\n" + << " input_coord = select(f32(output_coord), " << transform_coordinate_caller << " , " << scales_index_str << " != 1.0);\n" + << extrapolation_ss.str() + << " input_coord = max(0.0, min(input_coord, input_max_coord));\n" + << " let input_x_coord_int = u32(input_coord);\n" + << " let x_weight_0 = select(input_coord - f32(input_x_coord_int), 0.5, input_coord >= input_max_coord);\n" + << " let end_of_h = (input_y_coord_int >= input_height - 1);\n" + << " let end_of_w = (input_x_coord_int >= input_width - 1);\n" + << " let rank = " << rank_ << ";\n" + << " input_indices[rank - 2] = input_y_coord_int;\n" + << " input_indices[rank - 1] = input_x_coord_int;\n" + << " let x00 = " << input.GetByIndices("input_indices") << ";\n" + << " input_indices[rank - 1] = input_x_coord_int + 1;\n" + << " let x10 = select(" << input.GetByIndices("input_indices") << ", x00, end_of_w);\n" + << " input_indices[rank - 2] = input_y_coord_int + 1;\n" + << " input_indices[rank - 1] = input_x_coord_int;\n" + << " let x01 = select(" << input.GetByIndices("input_indices") << ", x00, end_of_h);\n" + << " input_indices[rank - 1] = input_x_coord_int + 1;\n" + << " let x11 = select(select(" << input.GetByIndices("input_indices") << ", x10, end_of_h), x01, end_of_w);\n" + << " let y_weight_1 = 1.0 - y_weight_0;\n" + << " let x_weight_1 = 1.0 - x_weight_0;\n" + << " var value = input_value_t(f32(x00) * y_weight_1 * x_weight_1 + f32(x01) * y_weight_0 * x_weight_1 + f32(x10) * " + << "y_weight_1 * x_weight_0 + f32(x11) * y_weight_0 * x_weight_0);\n" + << " " << output.SetByOffset("global_idx", "value"); + + return Status::OK(); +} + +Status ResizeBilinearImpl(ComputeContext& context, + const Tensor* input_tensor, + int32_t rank, + gsl::span& output_dims, + gsl::span roi, + gsl::span scales, + bool extrapolation_enabled, + const float extrapolation_value, + onnxruntime::ResizeCoordinateTransformationMode coordinate_transform_mode) { + TensorShape output_shape(output_dims); + auto* output_tensor = context.Output(0, output_shape); + uint32_t output_size = onnxruntime::narrow(output_shape.Size()); + + ResizeBilinearProgram program{coordinate_transform_mode, extrapolation_enabled, rank}; + program.AddInput({input_tensor, ProgramTensorMetadataDependency::TypeAndRank}) + .AddOutput({output_tensor, ProgramTensorMetadataDependency::Rank}) + .SetDispatchGroupSize((output_size + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE) + .CacheHint(std::to_string(static_cast(extrapolation_enabled)), + std::to_string(static_cast(coordinate_transform_mode))) + .AddUniformVariables({{roi}, {scales}, {output_size}, {extrapolation_value}}); + + return context.RunProgram(program); +} + +Status ResizeTrilinearProgram::GenerateShaderCode(ShaderHelper& shader) const { + const ShaderVariableHelper& input = shader.AddInput("input", ShaderUsage::UseUniform | + ShaderUsage::UseShapeAndStride | + ShaderUsage::UseValueTypeAlias); + const ShaderVariableHelper& output = shader.AddOutput("output", ShaderUsage::UseUniform | + ShaderUsage::UseShapeAndStride); + + std::string scales_index_str = GetElementAt("uniforms.scales", "axis", rank_); + std::string input_shape_index_str = GetElementAt("uniforms.input_shape", "axis", rank_); + + std::stringstream extrapolation_ss; + if (extrapolation_enabled_) { + extrapolation_ss << " if ((input_coord < 0.0 || input_coord > f32(" << input_shape_index_str << " - 1))) {\n" + << " " << output.SetByOffset("global_idx", "input_value_t(uniforms.extrapolation_value)") << ";\n" + << " return;\n" + << " }\n"; + } + + TransformCoordinate(shader.AdditionalImplementation(), coordinate_transform_mode_); + std::string transform_coordinate_caller = GetCoordinateCaller(coordinate_transform_mode_, rank_); + shader.MainFunctionBody() << shader.GuardAgainstOutOfBoundsWorkgroupSizes("uniforms.output_size") + << " let output_indices = " << output.OffsetToIndices("global_idx") << ";\n" + << " var input_indices = " << output.OffsetToIndices("global_idx") << ";\n" + << " var axis = " << rank_ - 3 << ";\n" + << " let input_depth = u32(" << input_shape_index_str << ");\n" + << " var input_max_coord = f32(input_depth - 1);\n" + << " var output_coord = output_indices[axis];\n" + << " var input_coord = select(f32(output_coord), " << transform_coordinate_caller << " , " << scales_index_str << " != 1.0);\n" + << extrapolation_ss.str() + << " input_coord = max(0.0, min(input_coord, input_max_coord));\n" + << " let input_z_coord_int = u32(input_coord);\n" + << " let z_weight_0 = select(input_coord - f32(input_z_coord_int), 0.5, input_coord >= input_max_coord);\n" + << " axis = " << rank_ - 2 << ";\n" + << " let input_height = u32(" << input_shape_index_str << ");\n" + << " input_max_coord = f32(input_height - 1);\n" + << " output_coord = output_indices[axis];\n" + << " input_coord = select(f32(output_coord), " << transform_coordinate_caller << " , " << scales_index_str << " != 1.0);\n" + << extrapolation_ss.str() + << " input_coord = max(0.0, min(input_coord, input_max_coord));\n" + << " let input_y_coord_int = u32(input_coord);\n" + << " let y_weight_0 = select(input_coord - f32(input_y_coord_int), 0.5, input_coord >= input_max_coord);\n" + << " axis = " << rank_ - 1 << ";\n" + << " let input_width = u32(" << input_shape_index_str << ");\n" + << " input_max_coord = f32(input_width - 1);\n" + << " output_coord = output_indices[axis];\n" + << " input_coord = select(f32(output_coord), " << transform_coordinate_caller << " , " << scales_index_str << " != 1.0);\n" + << extrapolation_ss.str() + << " input_coord = max(0.0, min(input_coord, input_max_coord));\n" + << " let input_x_coord_int = u32(input_coord);\n" + << " let x_weight_0 = select(input_coord - f32(input_x_coord_int), 0.5, input_coord >= input_max_coord);\n" + << " let end_of_d = (input_z_coord_int >= input_depth - 1);\n" + << " let end_of_h = (input_y_coord_int >= input_height - 1);\n" + << " let end_of_w = (input_x_coord_int >= input_width - 1);\n" + << " let rank = " << rank_ << ";\n" + << " input_indices[rank - 3] = input_z_coord_int;\n" + << " input_indices[rank - 2] = input_y_coord_int;\n" + << " input_indices[rank - 1] = input_x_coord_int;\n" + << " let x000 = " << input.GetByIndices("input_indices") << ";\n" + << " input_indices[rank - 1] = input_x_coord_int + 1;\n" + << " let x100 = select(" << input.GetByIndices("input_indices") << ", x000, end_of_w);\n" + << " input_indices[rank - 2] = input_y_coord_int + 1;\n" + << " input_indices[rank - 1] = input_x_coord_int;\n" + << " let x010 = select(" << input.GetByIndices("input_indices") << ", x000, end_of_h);\n" + << " input_indices[rank - 1] = input_x_coord_int + 1;\n" + << " let x110 = select(select(" << input.GetByIndices("input_indices") << ", x100, end_of_h), x010, end_of_w);\n" + << " input_indices[rank - 1] = input_x_coord_int;\n" + << " input_indices[rank - 2] = input_y_coord_int;\n" + << " input_indices[rank - 3] = select(input_z_coord_int + 1, input_z_coord_int, end_of_d);\n" + << " let x001 = select(" << input.GetByIndices("input_indices") << ", x000, end_of_d);\n" + << " input_indices[rank - 1] = input_x_coord_int + 1;\n" + << " let x101 = select(" << input.GetByIndices("input_indices") << ", x001, end_of_w);\n" + << " input_indices[rank - 2] = input_y_coord_int + 1;\n" + << " input_indices[rank - 1] = input_x_coord_int;\n" + << " let x011 = select(" << input.GetByIndices("input_indices") << ", x001, end_of_h);\n" + << " input_indices[rank - 1] = input_x_coord_int + 1;\n" + << " let x111 = select(select(" << input.GetByIndices("input_indices") << ", x101, end_of_h), x011, end_of_w);\n" + << " let z_weight_1 = 1.0 - z_weight_0;\n" + << " let y_weight_1 = 1.0 - y_weight_0;\n" + << " let x_weight_1 = 1.0 - x_weight_0;\n" + << " var value = input_value_t(" + << "f32(x000) * z_weight_1 * y_weight_1 * x_weight_1 + f32(x010) * z_weight_1 * y_weight_0 * x_weight_1 + " + << "f32(x100) * z_weight_1 * y_weight_1 * x_weight_0 + f32(x110) * z_weight_1 * y_weight_0 * x_weight_0 + " + << "f32(x001) * z_weight_0 * y_weight_1 * x_weight_1 + f32(x011) * z_weight_0 * y_weight_0 * x_weight_1 + " + << "f32(x101) * z_weight_0 * y_weight_1 * x_weight_0 + f32(x111) * z_weight_0 * y_weight_0 * x_weight_0" + << ");\n" + << " " << output.SetByOffset("global_idx", "value"); + + return Status::OK(); +} + +Status ResizeTrilinearImpl(ComputeContext& context, + const Tensor* input_tensor, + int32_t rank, + gsl::span& output_dims, + gsl::span roi, + gsl::span scales, + bool extrapolation_enabled, + const float extrapolation_value, + onnxruntime::ResizeCoordinateTransformationMode coordinate_transform_mode) { + TensorShape output_shape(output_dims); + auto* output_tensor = context.Output(0, output_shape); + uint32_t output_size = onnxruntime::narrow(output_shape.Size()); + + ResizeTrilinearProgram program{coordinate_transform_mode, extrapolation_enabled, rank}; + program.AddInput({input_tensor, ProgramTensorMetadataDependency::TypeAndRank}) + .AddOutput({output_tensor, ProgramTensorMetadataDependency::Rank}) + .SetDispatchGroupSize((output_size + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE) + .CacheHint(std::to_string(static_cast(extrapolation_enabled)), + std::to_string(static_cast(coordinate_transform_mode))) + .AddUniformVariables({{roi}, {scales}, {output_size}, {extrapolation_value}}); + + return context.RunProgram(program); +} + +Status ResizeBiCubicProgram::GenerateShaderCode(ShaderHelper& shader) const { + const ShaderVariableHelper& input = shader.AddInput("input", ShaderUsage::UseUniform | + ShaderUsage::UseShapeAndStride | + ShaderUsage::UseValueTypeAlias); + const ShaderVariableHelper& output = shader.AddOutput("output", ShaderUsage::UseUniform | + ShaderUsage::UseShapeAndStride); + + std::string scales_index_str = GetElementAt("uniforms.scales", "axis", rank_); + std::string input_shape_index_str = GetElementAt("uniforms.input_shape", "axis", rank_); + + std::stringstream exclude_outside_ss; + std::stringstream extrapolation_enabled_ss; + if (exclude_outside_) { + exclude_outside_ss << " coeff[0] = select(coeff[0], 0.0, (input_coord_int - 1 < 0 || input_coord_int - 1 >= input_max_coord));\n" + << " coeff[1] = select(coeff[1], 0.0, (input_coord_int + 0 < 0 || input_coord_int + 0 >= input_max_coord));\n" + << " coeff[2] = select(coeff[2], 0.0, (input_coord_int + 1 < 0 || input_coord_int + 1 >= input_max_coord));\n" + << " coeff[3] = select(coeff[3], 0.0, (input_coord_int + 2 < 0 || input_coord_int + 2 >= input_max_coord));\n" + << " coeff_sum = dot(coeff, vec4(1.0));\n"; + } + + if (extrapolation_enabled_) { + extrapolation_enabled_ss << " if ((input_coord < 0.0 || input_coord > f32(input_max_coord - 1))) {\n" + << " " << output.SetByOffset("global_idx", "input_value_t(uniforms.extrapolation_value)") << ";\n" + << " return;\n" + << " }\n"; + } + + std::stringstream coeff_ss; + coeff_ss << " coeff[0] = ((cubic_coeff_a * (s_coord + 1.0) - 5.0 * cubic_coeff_a) * (s_coord + 1.0) + 8.0 * cubic_coeff_a) * (s_coord + 1.0) - 4.0 * cubic_coeff_a;\n" + << " coeff[1] = ((cubic_coeff_a + 2.0) * s_coord - (cubic_coeff_a + 3.0)) * s_coord * s_coord + 1.0;\n" + << " coeff[2] = ((cubic_coeff_a + 2.0) * (1.0 - s_coord) - (cubic_coeff_a + 3.0)) * (1.0 - s_coord) * (1.0 - s_coord) + 1.0;\n" + << " coeff[3] = ((cubic_coeff_a * (2.0 - s_coord) - 5.0 * cubic_coeff_a) * (2.0 - s_coord) + 8.0 * cubic_coeff_a) * (2.0 - s_coord) - 4.0 * cubic_coeff_a;\n"; + + std::stringstream cubic_interpolation_rowwise_ss; + cubic_interpolation_rowwise_ss << " input_indices[" << rank_ - 2 << "] = u32(clamp(y, 0, input_height - 1));\n" + << " input_indices[" << rank_ - 1 << "] = u32(clamp(input_x_coord_int - 1, 0, input_width - 1));\n" + << " value_rowwise = x_coeff[0] * " << input.GetByIndices("input_indices") << ";\n" + << " input_indices[" << rank_ - 1 << "] = u32(clamp(input_x_coord_int, 0, input_width - 1));\n" + << " value_rowwise += x_coeff[1] * " << input.GetByIndices("input_indices") << ";\n" + << " input_indices[" << rank_ - 1 << "] = u32(clamp(input_x_coord_int + 1, 0, input_width - 1));\n" + << " value_rowwise += x_coeff[2] * " << input.GetByIndices("input_indices") << ";\n" + << " input_indices[" << rank_ - 1 << "] = u32(clamp(input_x_coord_int + 2, 0, input_width - 1));\n" + << " value_rowwise += x_coeff[3] * " << input.GetByIndices("input_indices") << ";\n"; + + TransformCoordinate(shader.AdditionalImplementation(), coordinate_transform_mode_); + std::string transform_coordinate_caller = GetCoordinateCaller(coordinate_transform_mode_, rank_); + shader.MainFunctionBody() << shader.GuardAgainstOutOfBoundsWorkgroupSizes("uniforms.output_size") + << " let output_indices = " << output.OffsetToIndices("global_idx") << ";\n" + << " var input_indices = " << output.OffsetToIndices("global_idx") << ";\n" + << " var axis = " << rank_ - 2 << ";\n" + << " let input_height = i32(" << input_shape_index_str << ");\n" + << " var input_max_coord = input_height;\n" + << " var output_coord = output_indices[axis];\n" + << " var input_coord = select(f32(output_coord), " << transform_coordinate_caller << " , " << scales_index_str << " != 1.0);\n" + << extrapolation_enabled_ss.str() + << " var coeff_sum = 1.0;\n" + << " let cubic_coeff_a = uniforms.cubic_coeff_a;\n" + << " var input_coord_int = i32(floor(input_coord));\n" + << " var s_coord = abs(input_coord - f32(input_coord_int));\n" + << " var coeff = vec4(0.0);\n" + << coeff_ss.str() + << exclude_outside_ss.str() + << " let input_y_coord_int = input_coord_int;\n" + << " let y_coeff = coeff / coeff_sum;\n" + << " axis = " << rank_ - 1 << ";\n" + << " let input_width = i32(" << input_shape_index_str << ");\n" + << " input_max_coord = input_width;\n" + << " output_coord = output_indices[axis];\n" + << " input_coord = select(f32(output_coord), " << transform_coordinate_caller << " , " << scales_index_str << " != 1.0);\n" + << extrapolation_enabled_ss.str() + << " input_coord_int = i32(floor(input_coord));\n" + << " s_coord = abs(input_coord - f32(input_coord_int));\n" + << coeff_ss.str() + << exclude_outside_ss.str() + << " let input_x_coord_int = input_coord_int;\n" + << " let x_coeff = coeff / coeff_sum;\n" + << " var y = input_y_coord_int - 1;\n" + << " var value_rowwise = 0.0;\n" + << " var value = 0.0;\n" + << cubic_interpolation_rowwise_ss.str() + << " value += y_coeff[0] * value_rowwise;\n" + << " y = input_y_coord_int;\n" + << cubic_interpolation_rowwise_ss.str() + << " value += y_coeff[1] * value_rowwise;\n" + << " y = input_y_coord_int + 1;\n" + << cubic_interpolation_rowwise_ss.str() + << " value += y_coeff[2] * value_rowwise;\n" + << " y = input_y_coord_int + 2;\n" + << cubic_interpolation_rowwise_ss.str() + << " value += y_coeff[3] * value_rowwise;\n" + << output.SetByOffset("global_idx", "input_value_t(value)"); + + return Status::OK(); +} + +Status ResizeBiCubicImpl(ComputeContext& context, + const Tensor* input_tensor, + int32_t rank, + gsl::span& output_dims, + gsl::span roi, + gsl::span scales, + bool extrapolation_enabled, + const float extrapolation_value, + float cubic_coeff_a, + bool exclude_outside, + onnxruntime::ResizeCoordinateTransformationMode coordinate_transform_mode) { + TensorShape output_shape(output_dims); + auto* output_tensor = context.Output(0, output_shape); + uint32_t output_size = onnxruntime::narrow(output_shape.Size()); + + ResizeBiCubicProgram program{coordinate_transform_mode, extrapolation_enabled, exclude_outside, rank}; + program.AddInput({input_tensor, ProgramTensorMetadataDependency::TypeAndRank}) + .AddOutput({output_tensor, ProgramTensorMetadataDependency::Rank}) + .SetDispatchGroupSize((output_size + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE) + .CacheHint(std::to_string(static_cast(extrapolation_enabled)), + std::to_string(static_cast(exclude_outside)), + std::to_string(static_cast(coordinate_transform_mode))) + .AddUniformVariables({{roi}, {scales}, {output_size}, {extrapolation_value}, {cubic_coeff_a}}); + + return context.RunProgram(program); +} + +Status ResizeImpl(ComputeContext& context, + const Tensor* input, + const onnxruntime::UpsampleMode upsample_mode, + gsl::span& output_dims, + gsl::span roi, + gsl::span scales, + bool extrapolation_enabled, + const float extrapolation_value, + float cubic_coeff_a, + bool exclude_outside, + onnxruntime::ResizeCoordinateTransformationMode coordinate_transform_mode, + onnxruntime::ResizeNearestMode nearest_mode) { + int32_t rank = static_cast(output_dims.size()); + // We support a special case of bilinear or bicubic if the input data is 4D with the outer 2 scales being 1.0 + // We would have validated the outer scale values by the time execution reaches this + bool is_2D = (rank == 2 || rank == 4); + + // We support a special case of trilinear or tricubic if the input data is 5D with the outer 2 scales being 1.0 + // We would have validated the outer scale values by the time execution reaches this + bool is_3D = (rank == 3 || rank == 5); + + // Should not hit this as we have already validated input rank/scales and we provide verbose error messages + // to the user. + ORT_ENFORCE(is_2D || is_3D, "Only bilinear/trilinear and bicubic modes are supported in Resize"); + + switch (upsample_mode) { + case UpsampleMode::NN: + return ResizeNearestImpl(context, input, rank, output_dims, roi, scales, extrapolation_enabled, + extrapolation_value, coordinate_transform_mode, nearest_mode); + break; + case UpsampleMode::LINEAR: + if (is_2D) { + return ResizeBilinearImpl(context, input, rank, output_dims, roi, scales, extrapolation_enabled, + extrapolation_value, coordinate_transform_mode); + } else if (is_3D) { + return ResizeTrilinearImpl(context, input, rank, output_dims, roi, scales, extrapolation_enabled, + extrapolation_value, coordinate_transform_mode); + } + ORT_THROW("Resize support 2-D and 3-D dimensions in LINEAR mode."); + break; + case UpsampleMode::CUBIC: + if (is_2D) { + return ResizeBiCubicImpl(context, input, rank, output_dims, roi, scales, extrapolation_enabled, + extrapolation_value, cubic_coeff_a, exclude_outside, coordinate_transform_mode); + } + ORT_THROW("Resize supports only 2-D in CUBIC mode."); + default: + ORT_THROW("Only nearest, bilinear/trilinear and bicubic modes are supported in Resize"); + } +} + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/tensor/resize_impl.h b/onnxruntime/core/providers/webgpu/tensor/resize_impl.h new file mode 100644 index 0000000000000..9bf622405355a --- /dev/null +++ b/onnxruntime/core/providers/webgpu/tensor/resize_impl.h @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/webgpu/webgpu_kernel.h" +#include "core/providers/webgpu/program.h" +#include "core/providers/cpu/tensor/upsample.h" + +namespace onnxruntime { +namespace webgpu { + +class ResizeNearestProgram final : public Program { + public: + ResizeNearestProgram(onnxruntime::ResizeCoordinateTransformationMode coordinate_transform_mode, + onnxruntime::ResizeNearestMode nearest_mode, + bool extrapolation_enabled, + int32_t rank) : Program{"ResizeNearest2D"}, + coordinate_transform_mode_{coordinate_transform_mode}, + nearest_mode_{nearest_mode}, + extrapolation_enabled_{extrapolation_enabled}, + rank_{rank} {} + + Status GenerateShaderCode(ShaderHelper& sh) const override; + + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"roi", ProgramUniformVariableDataType::Float32}, + {"scales", ProgramUniformVariableDataType::Float32}, + {"output_size", ProgramUniformVariableDataType::Uint32}, + {"extrapolation_value", ProgramUniformVariableDataType::Float32}); + + private: + onnxruntime::ResizeCoordinateTransformationMode coordinate_transform_mode_; + onnxruntime::ResizeNearestMode nearest_mode_; + bool extrapolation_enabled_; + int32_t rank_; +}; + +class ResizeBilinearProgram final : public Program { + public: + ResizeBilinearProgram(onnxruntime::ResizeCoordinateTransformationMode coordinate_transform_mode, + bool extrapolation_enabled, + int32_t rank) : Program{"ResizeBilinear"}, + coordinate_transform_mode_{coordinate_transform_mode}, + extrapolation_enabled_{extrapolation_enabled}, + rank_{rank} {} + + Status GenerateShaderCode(ShaderHelper& sh) const override; + + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"roi", ProgramUniformVariableDataType::Float32}, + {"scales", ProgramUniformVariableDataType::Float32}, + {"output_size", ProgramUniformVariableDataType::Uint32}, + {"extrapolation_value", ProgramUniformVariableDataType::Float32}); + + private: + onnxruntime::ResizeCoordinateTransformationMode coordinate_transform_mode_; + bool extrapolation_enabled_; + int32_t rank_; +}; + +class ResizeTrilinearProgram final : public Program { + public: + ResizeTrilinearProgram(onnxruntime::ResizeCoordinateTransformationMode coordinate_transform_mode, + bool extrapolation_enabled, + int32_t rank) : Program{"ResizeTrilinear"}, + coordinate_transform_mode_{coordinate_transform_mode}, + extrapolation_enabled_{extrapolation_enabled}, + rank_{rank} {} + + Status GenerateShaderCode(ShaderHelper& sh) const override; + + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"roi", ProgramUniformVariableDataType::Float32}, + {"scales", ProgramUniformVariableDataType::Float32}, + {"output_size", ProgramUniformVariableDataType::Uint32}, + {"extrapolation_value", ProgramUniformVariableDataType::Float32}); + + private: + onnxruntime::ResizeCoordinateTransformationMode coordinate_transform_mode_; + bool extrapolation_enabled_; + int32_t rank_; +}; + +class ResizeBiCubicProgram final : public Program { + public: + ResizeBiCubicProgram(onnxruntime::ResizeCoordinateTransformationMode coordinate_transform_mode, + bool extrapolation_enabled, + bool exclude_outside, + int32_t rank) : Program{"ResizeBiCubic"}, + coordinate_transform_mode_{coordinate_transform_mode}, + extrapolation_enabled_{extrapolation_enabled}, + exclude_outside_{exclude_outside}, + rank_{rank} {} + + Status GenerateShaderCode(ShaderHelper& sh) const override; + + WEBGPU_PROGRAM_DEFINE_UNIFORM_VARIABLES({"roi", ProgramUniformVariableDataType::Float32}, + {"scales", ProgramUniformVariableDataType::Float32}, + {"output_size", ProgramUniformVariableDataType::Uint32}, + {"extrapolation_value", ProgramUniformVariableDataType::Float32}, + {"cubic_coeff_a", ProgramUniformVariableDataType::Float32}); + + private: + onnxruntime::ResizeCoordinateTransformationMode coordinate_transform_mode_; + bool extrapolation_enabled_; + bool exclude_outside_; + int32_t rank_; +}; + +Status ResizeImpl( + ComputeContext& context, + const Tensor* input, + const onnxruntime::UpsampleMode upsample_mode, + gsl::span& output_dims, + gsl::span roi, + gsl::span scales, + bool extrapolation_enabled, + const float extrapolation_value, + float cubic_coeff_a, + bool exclude_outside, + onnxruntime::ResizeCoordinateTransformationMode coordinate_transform_mode, + onnxruntime::ResizeNearestMode nearest_mode); + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/tensor/split.cc b/onnxruntime/core/providers/webgpu/tensor/split.cc index 83bf832cc5b11..150b0beb897f5 100644 --- a/onnxruntime/core/providers/webgpu/tensor/split.cc +++ b/onnxruntime/core/providers/webgpu/tensor/split.cc @@ -29,20 +29,16 @@ void WriteBufferData(std::ostream& os, const ShaderVariableHelper& input, for (size_t i = 0; i < outputs.size(); ++i) { const auto buffer_write = outputs[i]->SetByIndices("indices", input.GetByOffset("global_idx")); if (outputs.size() == 1) { - os << buffer_write; + os << buffer_write << "\n"; } else if (i == 0) { - os << " if (output_number == 0u) {\n" - << " " << buffer_write << "\n"; + os << " if (output_number == 0u) { " << buffer_write << " }\n"; } else if (i == outputs.size() - 1) { - os << " } else {\n" - << " " << buffer_write << "\n"; + os << " else { " << buffer_write << " }\n"; } else { - os << " } else if (output_number == " << i << "u) {\n" - << " " << buffer_write << "\n"; + os << " else if (output_number == " << i << "u) { " << buffer_write << " }\n"; } } - os << " }\n" - << "}\n"; + os << "}\n"; } } // namespace @@ -68,7 +64,7 @@ Status SplitProgram::GenerateShaderCode(ShaderHelper& shader) const { << " var index = " << input.IndicesGet("indices", axis_) << ";\n" << " let output_number = calculate_output_index(index);\n" << " if (output_number != 0u) {\n" - << " index -= uniforms.sizes_in_split_axis[output_number - 1u];\n" + << " index -= " << GetElementAt("uniforms.sizes_in_split_axis", "output_number - 1u", output_count) << ";\n" << " " << input.IndicesSet("indices", axis_, "index") << "\n" << " }\n" << " write_buffer_data(output_number, global_idx, indices);\n"; @@ -107,7 +103,7 @@ Status Split::ComputeInternal(ComputeContext& context) const { ORT_RETURN_IF_ERROR(PrepareForCompute(input_shape, num_outputs, axis, before_dims, after_dims_including_split_axis, after_dims_excluding_split, split_sizes)); - SplitProgram program{gsl::narrow_cast(axis)}; + SplitProgram program{static_cast(axis)}; program.AddInput({input, ProgramTensorMetadataDependency::TypeAndRank}); auto output_dimensions = input_shape.AsShapeVector(); @@ -120,7 +116,7 @@ Status Split::ComputeInternal(ComputeContext& context) const { program.AddOutput({output, ProgramTensorMetadataDependency::Rank}); } - uint32_t input_size = gsl::narrow(input_shape.Size()); + uint32_t input_size = onnxruntime::narrow(input_shape.Size()); // Early return if the input tensor is empty. if (input_size == 0) { return Status::OK(); @@ -130,7 +126,7 @@ Status Split::ComputeInternal(ComputeContext& context) const { std::vector sizes_in_split_axis; // sizes_in_split_axis are the cumulative sizes of the splits in the split axis. for (auto split_size : split_sizes) { - previous_sum += gsl::narrow(split_size); + previous_sum += onnxruntime::narrow(split_size); sizes_in_split_axis.push_back(previous_sum); } diff --git a/onnxruntime/core/providers/webgpu/tensor/transpose.cc b/onnxruntime/core/providers/webgpu/tensor/transpose.cc index c40ec43dd0009..0df7d1ae9fa2f 100644 --- a/onnxruntime/core/providers/webgpu/tensor/transpose.cc +++ b/onnxruntime/core/providers/webgpu/tensor/transpose.cc @@ -47,7 +47,10 @@ ONNX_OPERATOR_KERNEL_EX( .TypeConstraint("T", WebGpuSupportedNumberTypes()), Transpose); -auto SqueezeShape(const gsl::span& shape, const gsl::span& adjusted_perm, InlinedVector& new_shape, InlinedVector& new_perm) { +auto SqueezeShape(const gsl::span& shape, + const gsl::span& adjusted_perm, + TensorShapeVector& new_shape, + TensorShapeVector& new_perm) { for (size_t i = 0; i < shape.size(); ++i) { if (shape[i] != 1) { new_shape.push_back(shape[i]); @@ -97,26 +100,28 @@ Status TransposeProgram::GenerateShaderCode(ShaderHelper& shader) const { return Status::OK(); } -Status Transpose::ComputeInternal(ComputeContext& context) const { - const auto* input_tensor = context.Input(0); - const TensorShape& input_shape = input_tensor->Shape(); - int32_t rank = gsl::narrow_cast(input_shape.NumDimensions()); +Status Transpose::DoTranspose(onnxruntime::webgpu::ComputeContext& context, + gsl::span permutations, + const Tensor& input, Tensor& output) { + const auto& input_shape = input.Shape(); + const auto& input_dims = input_shape.GetDims(); + int32_t rank = static_cast(input_shape.NumDimensions()); TensorShapeVector output_dims(rank); - InlinedVector default_perm(rank); - const InlinedVector* p_perm = nullptr; - ORT_RETURN_IF_ERROR(ComputeOutputShape(*input_tensor, output_dims, default_perm, p_perm)); - TensorShape output_shape(output_dims); - auto* output_tensor = context.Output(0, output_shape); - InlinedVector new_shape{}; - InlinedVector new_perm{}; - SqueezeShape(input_shape.GetDims(), *p_perm, new_shape, new_perm); - const bool channels_last = new_perm == InlinedVector({2, 3, 1}); - const bool channels_first = new_perm == InlinedVector({3, 1, 2}); + for (int32_t i = 0; i < rank; i++) { + output_dims[i] = input_dims[permutations[i]]; + } + + TensorShapeVector new_shape{}; + TensorShapeVector new_perm{}; + SqueezeShape(input_shape.GetDims(), permutations, new_shape, new_perm); + const bool channels_last = new_perm == TensorShapeVector({2, 3, 1}); + const bool channels_first = new_perm == TensorShapeVector({3, 1, 2}); const bool use_shared = (new_shape.size() == 2 && new_perm[0] > new_perm[1]) || channels_last || channels_first; auto new_input_shape = input_shape; TensorShape new_output_shape(output_dims); + if (use_shared) { new_input_shape = channels_last ? TensorShape({new_shape[0], new_shape[1] * new_shape[2]}) @@ -126,16 +131,16 @@ Status Transpose::ComputeInternal(ComputeContext& context) const { new_output_shape = TensorShape({new_input_shape[1], new_input_shape[0]}); } - uint32_t output_size = gsl::narrow_cast(input_tensor->Shape().Size()); - TransposeProgram program{*p_perm, use_shared}; + uint32_t output_size = onnxruntime::narrow(input_shape.Size()); + TransposeProgram program{permutations, use_shared}; + if (use_shared) { program.SetWorkgroupSize(TILE_SIZE, TILE_SIZE, 1); } - program - .CacheHint(absl::StrJoin(*p_perm, "-")) - .AddInputs({{input_tensor, ProgramTensorMetadataDependency::TypeAndRank, new_input_shape, 1}}) - .AddOutputs({{output_tensor, ProgramTensorMetadataDependency::None, new_output_shape, 1}}) + .CacheHint(absl::StrJoin(permutations, "-")) + .AddInputs({{&input, ProgramTensorMetadataDependency::TypeAndRank, new_input_shape, 1}}) + .AddOutputs({{&output, ProgramTensorMetadataDependency::None, new_output_shape, 1}}) .SetDispatchGroupSize(static_cast((new_output_shape[1] + TILE_SIZE - 1) / TILE_SIZE), static_cast(((new_output_shape[0] + TILE_SIZE - 1) / TILE_SIZE))) .AddUniformVariables({ @@ -148,5 +153,20 @@ Status Transpose::ComputeInternal(ComputeContext& context) const { return context.RunProgram(program); } +Status Transpose::ComputeInternal(ComputeContext& context) const { + const auto* input_tensor = context.Input(0); + const TensorShape& input_shape = input_tensor->Shape(); + int32_t rank = static_cast(input_shape.NumDimensions()); + + TensorShapeVector output_dims(rank); + InlinedVector default_perm(rank); + const InlinedVector* p_perm = nullptr; + ORT_RETURN_IF_ERROR(ComputeOutputShape(*input_tensor, output_dims, default_perm, p_perm)); + TensorShape output_shape(output_dims); + auto* output_tensor = context.Output(0, output_shape); + + return DoTranspose(context, *p_perm, *input_tensor, *output_tensor); +} + } // namespace webgpu } // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/tensor/transpose.h b/onnxruntime/core/providers/webgpu/tensor/transpose.h index 7cf5c1fe0865d..b62a419fa12bc 100644 --- a/onnxruntime/core/providers/webgpu/tensor/transpose.h +++ b/onnxruntime/core/providers/webgpu/tensor/transpose.h @@ -16,6 +16,8 @@ class Transpose final : public WebGpuKernel, public TransposeBase { Transpose(const OpKernelInfo& info) : WebGpuKernel{info}, TransposeBase{info} { } Status ComputeInternal(ComputeContext& context) const override; + static Status DoTranspose(onnxruntime::webgpu::ComputeContext& context, gsl::span permutations, const Tensor& input, Tensor& output); + constexpr static uint32_t TILE_SIZE = 16; }; diff --git a/onnxruntime/core/providers/webgpu/tensor/upsample.cc b/onnxruntime/core/providers/webgpu/tensor/upsample.cc new file mode 100644 index 0000000000000..fb406883ba4ba --- /dev/null +++ b/onnxruntime/core/providers/webgpu/tensor/upsample.cc @@ -0,0 +1,132 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/webgpu/tensor/resize_impl.h" +#include "core/providers/webgpu/shader_helper.h" +#include "core/providers/webgpu/tensor/upsample.h" +#include "core/providers/webgpu/webgpu_supported_types.h" + +using namespace onnxruntime::common; + +namespace onnxruntime { +namespace webgpu { + +Status Upsample::BaseCompute(ComputeContext& context, + gsl::span roi, + gsl::span scales, + gsl::span output_dims) const { + const auto* X = context.Input(0); + auto dims = X->Shape().GetDims(); + ORT_ENFORCE(output_dims.size() == dims.size(), "Rank of input and output tensor should be same."); + + if (dims.size() == 0) { + return Status(ONNXRUNTIME, INVALID_ARGUMENT, + is_resize_ ? "Resize: input tensor cannot be scalar." + : "Upsample: input tensor cannot be scalar."); + } + if (dims.size() != scales.size()) { + return Status(ONNXRUNTIME, INVALID_ARGUMENT, + is_resize_ ? "Resize: input tensor's dimension does not match the scales." + : "Upsample: input tensor's dimension does not match the scales."); + } + if (roi.size() != 2 * dims.size()) { + return Status(ONNXRUNTIME, INVALID_ARGUMENT, + "Resize: size of roi array should be 2 * N where N is the rank of input tensor X."); + } + + Tensor* Y = context.Output(0, output_dims); + // Return early if the output tensor is going to be of size 0 + if (Y->Shape().Size() == 0) { + return Status::OK(); + } + + if (is_resize_) { + if (!antialias_) { + return ResizeImpl(context, X, mode_, output_dims, roi, scales, use_extrapolation_, extrapolation_value_, + cubic_coeff_a_, exclude_outside_, coordinate_transform_mode_, nearest_mode_); + } else { + return ORT_MAKE_STATUS(ONNXRUNTIME, NOT_IMPLEMENTED, + "The antialias attribute of Resize operator is NOT implemented."); + } + } else { + return ORT_MAKE_STATUS(ONNXRUNTIME, NOT_IMPLEMENTED, "Upsample operator is NOT implemented."); + } +} + +Status Upsample::ComputeInternal(ComputeContext& context) const { + const auto* X = context.Input(0); + auto input_dims = X->Shape().GetDims(); + TensorShapeVector output_dims(input_dims.size()); + + // Get roi data + // Initialize the roi array to all zeros as this will be the most common case + // Roi data is needed only when coordinate transformation mode is set to tf_crop_and_resize + // for all other cases we need a 0 initialized roi array + InlinedVector roi_array(roi_); + + if (!roi_cached_) { + bool use_default_roi = true; + if (need_roi_input_) { + ORT_ENFORCE(roi_input_idx_ > 0, "Invalid roi input index."); + const auto* roi = context.Input(roi_input_idx_); + if (roi != nullptr) { + ParseRoiData(roi, roi_array); + use_default_roi = false; + } + } + if (use_default_roi) { + // default roi includes ensures all the values in that axis are included in the roi + // normalized roi is thus : [start, end] = [0, 1] + size_t input_rank = input_dims.size(); + roi_array.resize(input_rank * 2); + for (size_t i = 0; i < input_rank; ++i) { + roi_array[i] = 0; + roi_array[i + input_rank] = 1; + } + } + } + + ComputeROIWithAxes(roi_array, input_dims.size()); + + InlinedVector scales_array(input_dims.size()); + // opset < 10 + if (OpKernel::Node().InputDefs().size() == 1) { + scales_array = scales_; + // Compute output shape from scales attributes and input dims + ComputeOutputShape(scales_array, input_dims, output_dims); + return BaseCompute(context, roi_array, scales_array, output_dims); + } + + const auto* scales = context.Input(scales_input_idx_); + const auto* sizes = context.Input(sizes_input_idx_); + + // This is when scales are obtained and cached from a constant initializer + if (scales_cached_) { + ORT_RETURN_IF_NOT(sizes == nullptr, "Only one of scales or sizes must be provided as input."); + scales_array = scales_; + // Compute output shape from scales and input dims + ComputeOutputShape(scales_array, input_dims, output_dims); + return BaseCompute(context, roi_array, scales_array, output_dims); + } + + // Scales and sizes are input to the node + if (scales != nullptr && scales->Shape().Size() != 0) { + // use scales input data + ORT_ENFORCE(sizes == nullptr, "Only one of scales or sizes must be provided as input."); + ORT_RETURN_IF_ERROR(ParseScalesData(scales, scales_array, input_dims.size())); + + // Compute output shape from scales and input dims + ComputeOutputShape(scales_array, input_dims, output_dims); + } else { + // When sizes input is available directly populate it into the output_dims array. + ORT_ENFORCE(sizes != nullptr && sizes->Shape().Size() != 0, + "Either scales or sizes MUST be provided as input."); + ORT_RETURN_IF_ERROR(ParseSizesData(sizes, output_dims, input_dims)); + ORT_RETURN_IF_ERROR(ParseScalesDataAndAdjustOutputSize(output_dims, input_dims, scales_array)); + } + + return BaseCompute(context, roi_array, scales_array, output_dims); +} + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/tensor/upsample.h b/onnxruntime/core/providers/webgpu/tensor/upsample.h new file mode 100644 index 0000000000000..ecfbc3c728703 --- /dev/null +++ b/onnxruntime/core/providers/webgpu/tensor/upsample.h @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/webgpu/webgpu_kernel.h" +#include "core/providers/webgpu/program.h" +#include "core/providers/cpu/tensor/upsample.h" + +namespace onnxruntime { +namespace webgpu { + +class Upsample : public UpsampleBase, public WebGpuKernel { + public: + explicit Upsample(const OpKernelInfo& info) : UpsampleBase(info), WebGpuKernel(info) {}; + + Status ComputeInternal(ComputeContext& context) const override; + Status BaseCompute(ComputeContext& context, gsl::span roi, gsl::span scales, + gsl::span output_dims) const; +}; + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/tensor/where.cc b/onnxruntime/core/providers/webgpu/tensor/where.cc index e8cdabb9dbe40..d7272ec525296 100644 --- a/onnxruntime/core/providers/webgpu/tensor/where.cc +++ b/onnxruntime/core/providers/webgpu/tensor/where.cc @@ -127,7 +127,7 @@ Status Where::ComputeInternal(ComputeContext& context) const { ORT_RETURN_IF_ERROR(ComputeOutputShape(cond_shape, x_shape, y_shape, output_shape)); auto* output_tensor = context.Output(0, output_shape); constexpr int component = 4; - uint32_t vec_size = gsl::narrow_cast((output_shape.Size() + 3) / component); + uint32_t vec_size = onnxruntime::narrow((output_shape.Size() + 3) / component); const auto is_broadcast = !(x_shape == y_shape && y_shape == cond_shape); WhereProgram program{is_broadcast}; diff --git a/onnxruntime/core/providers/webgpu/webgpu_context.cc b/onnxruntime/core/providers/webgpu/webgpu_context.cc index 163dd691b7f16..2987d3905fe54 100644 --- a/onnxruntime/core/providers/webgpu/webgpu_context.cc +++ b/onnxruntime/core/providers/webgpu/webgpu_context.cc @@ -110,7 +110,7 @@ void WebGpuContext::Initialize(const WebGpuBufferCacheConfig& buffer_cache_confi device_desc.requiredFeatures = required_features.data(); device_desc.requiredFeatureCount = required_features.size(); } - wgpu::RequiredLimits required_limits = GetRequiredLimits(adapter); + wgpu::Limits required_limits = GetRequiredLimits(adapter); device_desc.requiredLimits = &required_limits; // TODO: revise temporary error handling @@ -134,12 +134,20 @@ void WebGpuContext::Initialize(const WebGpuBufferCacheConfig& buffer_cache_confi ORT_ENFORCE(device_ != nullptr, "Failed to get a WebGPU device."); } + LOGS_DEFAULT(VERBOSE) << "WebGPU EP Context is created for: Instance=" << instance_.Get() << ", Device=" << device_.Get() << "."; + + // cache device queue + device_queue_ = device_.GetQueue(); // cache adapter info ORT_ENFORCE(Device().GetAdapterInfo(&adapter_info_)); // cache device limits - wgpu::SupportedLimits device_supported_limits; - ORT_ENFORCE(Device().GetLimits(&device_supported_limits)); - device_limits_ = device_supported_limits.limits; + ORT_ENFORCE(Device().GetLimits(&device_limits_)); + // cache device features + wgpu::SupportedFeatures supported_features; + Device().GetFeatures(&supported_features); + for (size_t i = 0; i < supported_features.featureCount; i++) { + device_features_.insert(supported_features.features[i]); + } // create buffer manager buffer_mgr_ = BufferManagerFactory::Create(*this, @@ -165,7 +173,6 @@ void WebGpuContext::Initialize(const WebGpuBufferCacheConfig& buffer_cache_confi #if defined(ENABLE_PIX_FOR_WEBGPU_EP) // set pix frame generator pix_frame_generator_ = std::make_unique(instance_, - Adapter(), Device()); #else ORT_THROW("Support PIX capture requires extra build flags (--enable_pix_capture)"); @@ -321,9 +328,9 @@ Status WebGpuContext::Run(ComputeContext& context, const ProgramBase& program) { std::vector dims(expected_rank); std::vector stride(expected_rank - 1); for (size_t j = 0; j < expected_rank; ++j) { - dims[j] = gsl::narrow(shape[j]); + dims[j] = onnxruntime::narrow(shape[j]); if (j < expected_rank - 1) { - stride[j] = gsl::narrow(shape.SizeFromDimension(j + 1)); + stride[j] = onnxruntime::narrow(shape.SizeFromDimension(j + 1)); } } @@ -395,7 +402,7 @@ Status WebGpuContext::Run(ComputeContext& context, const ProgramBase& program) { } uniform_buffer = buffer_mgr_->Create(uniform_buffer_total_size, wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Uniform); - device_.GetQueue().WriteBuffer(uniform_buffer, 0, uniform_data_buffer.data(), uniform_buffer_total_size); + device_queue_.WriteBuffer(uniform_buffer, 0, uniform_data_buffer.data(), uniform_buffer_total_size); } const auto& compute_pass_encoder = GetComputePassEncoder(); @@ -491,7 +498,10 @@ std::vector WebGpuContext::GetAvailableRequiredFeatures(const wgpu::FeatureName::TimestampQuery, wgpu::FeatureName::ShaderF16, wgpu::FeatureName::Subgroups, - wgpu::FeatureName::SubgroupsF16}; +#if !defined(__wasm__) + wgpu::FeatureName::BufferMapExtendedUsages, +#endif + }; for (auto feature : features) { if (adapter.HasFeature(feature)) { required_features.push_back(feature); @@ -500,20 +510,20 @@ std::vector WebGpuContext::GetAvailableRequiredFeatures(const return required_features; } -wgpu::RequiredLimits WebGpuContext::GetRequiredLimits(const wgpu::Adapter& adapter) const { - wgpu::RequiredLimits required_limits{}; - wgpu::SupportedLimits adapter_limits; +wgpu::Limits WebGpuContext::GetRequiredLimits(const wgpu::Adapter& adapter) const { + wgpu::Limits required_limits{}; + wgpu::Limits adapter_limits; ORT_ENFORCE(adapter.GetLimits(&adapter_limits)); - required_limits.limits.maxBindGroups = adapter_limits.limits.maxBindGroups; - required_limits.limits.maxComputeWorkgroupStorageSize = adapter_limits.limits.maxComputeWorkgroupStorageSize; - required_limits.limits.maxComputeWorkgroupsPerDimension = adapter_limits.limits.maxComputeWorkgroupsPerDimension; - required_limits.limits.maxStorageBufferBindingSize = adapter_limits.limits.maxStorageBufferBindingSize; - required_limits.limits.maxBufferSize = adapter_limits.limits.maxBufferSize; - required_limits.limits.maxComputeInvocationsPerWorkgroup = adapter_limits.limits.maxComputeInvocationsPerWorkgroup; - required_limits.limits.maxComputeWorkgroupSizeX = adapter_limits.limits.maxComputeWorkgroupSizeX; - required_limits.limits.maxComputeWorkgroupSizeY = adapter_limits.limits.maxComputeWorkgroupSizeY; - required_limits.limits.maxComputeWorkgroupSizeZ = adapter_limits.limits.maxComputeWorkgroupSizeZ; + required_limits.maxBindGroups = adapter_limits.maxBindGroups; + required_limits.maxComputeWorkgroupStorageSize = adapter_limits.maxComputeWorkgroupStorageSize; + required_limits.maxComputeWorkgroupsPerDimension = adapter_limits.maxComputeWorkgroupsPerDimension; + required_limits.maxStorageBufferBindingSize = adapter_limits.maxStorageBufferBindingSize; + required_limits.maxBufferSize = adapter_limits.maxBufferSize; + required_limits.maxComputeInvocationsPerWorkgroup = adapter_limits.maxComputeInvocationsPerWorkgroup; + required_limits.maxComputeWorkgroupSizeX = adapter_limits.maxComputeWorkgroupSizeX; + required_limits.maxComputeWorkgroupSizeY = adapter_limits.maxComputeWorkgroupSizeY; + required_limits.maxComputeWorkgroupSizeZ = adapter_limits.maxComputeWorkgroupSizeZ; return required_limits; } @@ -684,7 +694,7 @@ void WebGpuContext::Flush() { } auto command_buffer = current_command_encoder_.Finish(); - Device().GetQueue().Submit(1, &command_buffer); + device_queue_.Submit(1, &command_buffer); BufferManager().RefreshPendingBuffers(); current_command_encoder_ = nullptr; num_pending_dispatches_ = 0; @@ -708,45 +718,42 @@ WebGpuContext& WebGpuContextFactory::CreateContext(const WebGpuContextConfig& co WGPUInstance instance = config.instance; WGPUDevice device = config.device; - if (context_id == 0) { - // context ID is preserved for the default context. User cannot use context ID 0 as a custom context. - ORT_ENFORCE(instance == nullptr && device == nullptr, - "WebGPU EP default context (contextId=0) must not have custom WebGPU instance or device."); - - std::call_once(init_default_flag_, [ + std::call_once(init_default_flag_, [ #if !defined(__wasm__) - dawn_proc_table = config.dawn_proc_table + dawn_proc_table = config.dawn_proc_table #endif - ]() { - // Step.1 - setup dawn proc table (only for non-WASM build) + ]() { + // Step.1 - setup dawn proc table (only for non-WASM build) #if !defined(__wasm__) - const DawnProcTable* dawn_procs = reinterpret_cast(dawn_proc_table); + const DawnProcTable* dawn_procs = reinterpret_cast(dawn_proc_table); #if defined(BUILD_DAWN_MONOLITHIC_LIBRARY) - ORT_ENFORCE(dawn_procs == nullptr, "setting DawnProcTable is not allowed when dynamically linked to webgpu_dawn."); + ORT_ENFORCE(dawn_procs == nullptr, "setting DawnProcTable is not allowed when dynamically linked to webgpu_dawn."); #else #if !defined(USE_EXTERNAL_DAWN) - if (dawn_procs == nullptr) { - dawn_procs = &dawn::native::GetProcs(); - } + if (dawn_procs == nullptr) { + dawn_procs = &dawn::native::GetProcs(); + } #else - ORT_ENFORCE(dawn_procs != nullptr, "DawnProcTable must be provided."); + ORT_ENFORCE(dawn_procs != nullptr, "DawnProcTable must be provided."); #endif - dawnProcSetProcs(dawn_procs); + dawnProcSetProcs(dawn_procs); #endif #endif - // Step.2 - Create wgpu::Instance -#if !defined(__wasm__) - wgpu::InstanceDescriptor instance_desc{}; - instance_desc.capabilities.timedWaitAnyEnable = true; - default_instance_ = wgpu::CreateInstance(&instance_desc); -#else - default_instance_ = wgpu::CreateInstance(nullptr); -#endif + // Step.2 - Create wgpu::Instance + wgpu::InstanceDescriptor instance_desc{}; + instance_desc.capabilities.timedWaitAnyEnable = true; + default_instance_ = wgpu::CreateInstance(&instance_desc); + + ORT_ENFORCE(default_instance_ != nullptr, "Failed to create wgpu::Instance."); + }); + + if (context_id == 0) { + // context ID is preserved for the default context. User cannot use context ID 0 as a custom context. + ORT_ENFORCE(instance == nullptr && device == nullptr, + "WebGPU EP default context (contextId=0) must not have custom WebGPU instance or device."); - ORT_ENFORCE(default_instance_ != nullptr, "Failed to create wgpu::Instance."); - }); instance = default_instance_.Get(); } else { // for context ID > 0, user must provide custom WebGPU instance and device. @@ -759,7 +766,7 @@ WebGpuContext& WebGpuContextFactory::CreateContext(const WebGpuContextConfig& co auto it = contexts_.find(context_id); if (it == contexts_.end()) { GSL_SUPPRESS(r.11) - auto context = std::unique_ptr(new WebGpuContext(instance, device, config.validation_mode)); + auto context = std::unique_ptr(new WebGpuContext(instance, device, config.validation_mode, config.preserve_device)); it = contexts_.emplace(context_id, WebGpuContextFactory::WebGpuContextInfo{std::move(context), 0}).first; } else if (context_id != 0) { ORT_ENFORCE(it->second.context->instance_.Get() == instance && @@ -785,7 +792,7 @@ void WebGpuContextFactory::ReleaseContext(int context_id) { auto it = contexts_.find(context_id); ORT_ENFORCE(it != contexts_.end(), "WebGPU EP context ID ", context_id, " is not found."); - if (--it->second.ref_count == 0) { + if (--it->second.ref_count == 0 && !it->second.context->preserve_device_) { contexts_.erase(it); } } @@ -800,5 +807,9 @@ void CleanupWebGpuContexts() { WebGpuContextFactory::Cleanup(); } +WGPUDevice GetDevice(int context_id) { + return WebGpuContextFactory::GetContext(context_id).Device().Get(); +} + } // namespace webgpu } // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/webgpu_context.h b/onnxruntime/core/providers/webgpu/webgpu_context.h index cb0e14f82610b..8ebb122103177 100644 --- a/onnxruntime/core/providers/webgpu/webgpu_context.h +++ b/onnxruntime/core/providers/webgpu/webgpu_context.h @@ -6,7 +6,7 @@ #include #include -#include +#include "core/providers/webgpu/webgpu_external_header.h" #include "core/common/common.h" #include "core/framework/library_handles.h" @@ -32,6 +32,7 @@ struct WebGpuContextConfig { WGPUDevice device; const void* dawn_proc_table; ValidationMode validation_mode; + bool preserve_device; }; struct WebGpuBufferCacheConfig { @@ -79,6 +80,7 @@ class WebGpuContext final { const wgpu::AdapterInfo& AdapterInfo() const { return adapter_info_; } const wgpu::Limits& DeviceLimits() const { return device_limits_; } + bool DeviceHasFeature(wgpu::FeatureName feature) const { return device_features_.find(feature) != device_features_.end(); } const wgpu::CommandEncoder& GetCommandEncoder() { if (!current_command_encoder_) { @@ -150,15 +152,15 @@ class WebGpuContext final { AtPasses }; - WebGpuContext(WGPUInstance instance, WGPUDevice device, webgpu::ValidationMode validation_mode) - : instance_{instance}, device_{device}, validation_mode_{validation_mode}, query_type_{TimestampQueryType::None} {} + WebGpuContext(WGPUInstance instance, WGPUDevice device, webgpu::ValidationMode validation_mode, bool preserve_device) + : instance_{instance}, device_{device}, validation_mode_{validation_mode}, query_type_{TimestampQueryType::None}, preserve_device_{preserve_device} {} ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(WebGpuContext); std::vector GetEnabledAdapterToggles() const; std::vector GetEnabledDeviceToggles() const; std::vector GetDisabledDeviceToggles() const; std::vector GetAvailableRequiredFeatures(const wgpu::Adapter& adapter) const; - wgpu::RequiredLimits GetRequiredLimits(const wgpu::Adapter& adapter) const; + wgpu::Limits GetRequiredLimits(const wgpu::Adapter& adapter) const; void WriteTimestamp(uint32_t query_index); struct PendingKernelInfo { @@ -203,8 +205,10 @@ class WebGpuContext final { webgpu::ValidationMode validation_mode_; + wgpu::Queue device_queue_; wgpu::AdapterInfo adapter_info_; wgpu::Limits device_limits_; + std::unordered_set device_features_; wgpu::CommandEncoder current_command_encoder_; wgpu::ComputePassEncoder current_compute_pass_encoder_; @@ -227,6 +231,7 @@ class WebGpuContext final { uint64_t gpu_timestamp_offset_ = 0; bool is_profiling_ = false; + bool preserve_device_; #if defined(ENABLE_PIX_FOR_WEBGPU_EP) std::unique_ptr pix_frame_generator_ = nullptr; diff --git a/onnxruntime/core/providers/webgpu/webgpu_execution_provider.cc b/onnxruntime/core/providers/webgpu/webgpu_execution_provider.cc index 87383fe197477..1d4fea09dd4a6 100644 --- a/onnxruntime/core/providers/webgpu/webgpu_execution_provider.cc +++ b/onnxruntime/core/providers/webgpu/webgpu_execution_provider.cc @@ -23,6 +23,7 @@ #include "core/providers/webgpu/webgpu_context.h" #include "core/providers/webgpu/data_transfer.h" +#include "core/providers/webgpu/external_data_loader.h" #include "core/providers/webgpu/webgpu_profiler.h" namespace onnxruntime { @@ -143,7 +144,8 @@ class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxD class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 11, 11, ReduceMax); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 12, 12, ReduceMax); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 13, 17, ReduceMax); -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 18, ReduceMax); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 18, 19, ReduceMax); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 20, ReduceMax); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 1, 10, ReduceMean); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 11, 12, ReduceMean); @@ -154,7 +156,8 @@ class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxD class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 11, 11, ReduceMin); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 12, 12, ReduceMin); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 13, 17, ReduceMin); -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 18, ReduceMin); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 18, 19, ReduceMin); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 20, ReduceMin); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 1, 10, ReduceProd); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 11, 12, ReduceProd); @@ -247,6 +250,8 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 16, class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 1, 12, Transpose); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 13, 20, Transpose); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 21, 22, Transpose); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 23, Transpose); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 11, 12, DepthToSpace); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 13, DepthToSpace); @@ -254,9 +259,11 @@ class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kMSInt class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kMSInternalNHWCDomain, 13, DepthToSpace); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 1, 10, Conv); -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 11, Conv); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 11, 21, Conv); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 22, Conv); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kMSInternalNHWCDomain, 1, 10, Conv); -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kMSInternalNHWCDomain, 11, Conv); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kMSInternalNHWCDomain, 11, 21, Conv); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kMSInternalNHWCDomain, 22, Conv); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 1, 10, ConvTranspose); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 11, ConvTranspose); @@ -294,12 +301,12 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 13, class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 1, 12, MatMul); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 13, MatMul); -class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 1, 10, float, ArgMax); -class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 11, 12, float, ArgMax); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 13, float, ArgMax); -class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 1, 10, float, ArgMin); -class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 11, 12, float, ArgMin); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 13, float, ArgMin); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 1, 10, ArgMax); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 11, 12, ArgMax); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 13, ArgMax); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 1, 10, ArgMin); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 11, 12, ArgMin); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 13, ArgMin); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 1, 10, Softmax); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 11, 12, Softmax); @@ -363,12 +370,15 @@ class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxD class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 11, 12, Pad); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 13, 17, Pad); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 18, 18, Pad); -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 19, Pad); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 19, 20, Pad); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 21, 22, Pad); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 23, Pad); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 1, 10, If); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 11, 12, If); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 13, 18, If); -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 19, If); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 19, 20, If); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 21, If); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 7, 8, BatchNormalization); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 9, 13, BatchNormalization); @@ -381,18 +391,11 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kMSInternalNHWCD class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 11, 13, CumSum); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 14, CumSum); -class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 10, 12, uint8_t, DequantizeLinear); -class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 10, 12, int8_t, DequantizeLinear); -class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 10, 12, int32_t, DequantizeLinear); -class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 13, 18, uint8_t, DequantizeLinear); -class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 13, 18, int8_t, DequantizeLinear); -class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 13, 18, int32_t, DequantizeLinear); -class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 19, 20, uint8_t, DequantizeLinear); -class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 19, 20, int8_t, DequantizeLinear); -class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 19, 20, int32_t, DequantizeLinear); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 21, uint8_t, DequantizeLinear); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 21, int8_t, DequantizeLinear); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 21, int32_t, DequantizeLinear); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 10, 12, DequantizeLinear); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 13, 18, DequantizeLinear); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 19, 20, DequantizeLinear); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 21, 22, DequantizeLinear); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kWebGpuExecutionProvider, kOnnxDomain, 23, DequantizeLinear); std::unique_ptr RegisterKernels() { auto kernel_registry = std::make_unique(); @@ -510,124 +513,130 @@ std::unique_ptr RegisterKernels() { BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, KERNEL_CREATE_INFO_VERSIONED(9, 15, Where), KERNEL_CREATE_INFO(16, Where), BuildKernelCreateInfo, BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, // BuildKernelCreateInfo, // BuildKernelCreateInfo, // BuildKernelCreateInfo, // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, @@ -650,11 +659,11 @@ std::unique_ptr RegisterKernels() { BuildKernelCreateInfo, BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, // BuildKernelCreateInfo, // BuildKernelCreateInfo, // BuildKernelCreateInfo, @@ -685,16 +694,19 @@ std::unique_ptr RegisterKernels() { // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, @@ -704,20 +716,15 @@ std::unique_ptr RegisterKernels() { BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, - // BuildKernelCreateInfo, + + KERNEL_CREATE_INFO_VERSIONED(10, 12, DequantizeLinear), + KERNEL_CREATE_INFO_VERSIONED(13, 18, DequantizeLinear), + KERNEL_CREATE_INFO_VERSIONED(19, 20, DequantizeLinear), + KERNEL_CREATE_INFO_VERSIONED(21, 22, DequantizeLinear), + KERNEL_CREATE_INFO(23, DequantizeLinear), + + BuildKernelCreateInfo, + BuildKernelCreateInfo, }; for (auto& function_table_entry : function_table) { @@ -754,12 +761,15 @@ std::vector WebGpuExecutionProvider::CreatePreferredAllocators() { return std::make_unique(context_); }, 0, false); - return std::vector{CreateAllocator(gpuBufferAllocatorCreationInfo)}; + auto preferred_allocators = std::vector{CreateAllocator(gpuBufferAllocatorCreationInfo)}; + allocator_ = reinterpret_cast(preferred_allocators[0].get()); + return preferred_allocators; } std::vector> WebGpuExecutionProvider::GetCapability( const onnxruntime::GraphViewer& graph, const IKernelLookup& kernel_lookup, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const { InlinedVector candidates; // `tenative_candidates` is a subset of `candidates`. @@ -821,6 +831,12 @@ std::unique_ptr WebGpuExecutionProvider::GetDataTran return std::make_unique(context_); } +#if defined(__wasm__) +std::unique_ptr WebGpuExecutionProvider::GetExternalDataLoader() const { + return std::make_unique(); +} +#endif + WebGpuExecutionProvider::~WebGpuExecutionProvider() { WebGpuContextFactory::ReleaseContext(context_id_); } @@ -831,6 +847,13 @@ std::unique_ptr WebGpuExecutionProvider::GetProfiler() { return profiler; } +Status WebGpuExecutionProvider::OnSessionInitializationEnd() { + if (allocator_ != nullptr) { + allocator_->OnSessionInitializationEnd(); + } + return Status::OK(); +} + Status WebGpuExecutionProvider::OnRunStart(const onnxruntime::RunOptions& /*run_options*/) { if (context_.ValidationMode() >= ValidationMode::Basic) { context_.PushErrorScope(); diff --git a/onnxruntime/core/providers/webgpu/webgpu_execution_provider.h b/onnxruntime/core/providers/webgpu/webgpu_execution_provider.h index 7a0ade97aa3df..15aec16210f16 100644 --- a/onnxruntime/core/providers/webgpu/webgpu_execution_provider.h +++ b/onnxruntime/core/providers/webgpu/webgpu_execution_provider.h @@ -20,6 +20,7 @@ KernelCreateInfo BuildKernelCreateInfo(); class WebGpuContext; enum class BufferCacheMode; class WebGpuProfiler; +class GpuBufferAllocator; } // namespace webgpu struct WebGpuExecutionProviderConfig { @@ -45,10 +46,14 @@ class WebGpuExecutionProvider : public IExecutionProvider { std::vector> GetCapability( const onnxruntime::GraphViewer& graph_viewer, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const override; std::shared_ptr GetKernelRegistry() const override; std::unique_ptr GetDataTransfer() const override; +#if defined(__wasm__) + std::unique_ptr GetExternalDataLoader() const override; +#endif DataLayout GetPreferredLayout() const override { return preferred_data_layout_; } @@ -59,6 +64,7 @@ class WebGpuExecutionProvider : public IExecutionProvider { bool ConcurrentRunSupported() const override { return false; } std::vector CreatePreferredAllocators() override; + Status OnSessionInitializationEnd() override; Status OnRunStart(const onnxruntime::RunOptions& run_options) override; Status OnRunEnd(bool sync_stream, const onnxruntime::RunOptions& run_options) override; @@ -84,6 +90,7 @@ class WebGpuExecutionProvider : public IExecutionProvider { bool is_graph_captured_ = false; int regular_run_count_before_graph_capture_ = 0; const int min_num_runs_before_cuda_graph_capture_ = 1; // required min regular runs before graph capture for the necessary memory allocations. + webgpu::GpuBufferAllocator* allocator_ = nullptr; }; } // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/webgpu_pix_frame_generator.cc b/onnxruntime/core/providers/webgpu/webgpu_pix_frame_generator.cc index 90b99b7b38bb1..9b287b7b7df99 100644 --- a/onnxruntime/core/providers/webgpu/webgpu_pix_frame_generator.cc +++ b/onnxruntime/core/providers/webgpu/webgpu_pix_frame_generator.cc @@ -11,7 +11,7 @@ namespace onnxruntime { namespace webgpu { -WebGpuPIXFrameGenerator::WebGpuPIXFrameGenerator(wgpu::Instance instance, wgpu::Adapter adapter, wgpu::Device device) { +WebGpuPIXFrameGenerator::WebGpuPIXFrameGenerator(wgpu::Instance instance, wgpu::Device device) { // Trivial window size for surface texture creation and provide frame concept for PIX. static constexpr uint32_t kWidth = 512u; static constexpr uint32_t kHeight = 512u; @@ -32,7 +32,7 @@ WebGpuPIXFrameGenerator::WebGpuPIXFrameGenerator(wgpu::Instance instance, wgpu:: wgpu::TextureFormat format; wgpu::SurfaceCapabilities capabilities; - surface_.GetCapabilities(adapter, &capabilities); + surface_.GetCapabilities(device.GetAdapter(), &capabilities); format = capabilities.formats[0]; wgpu::SurfaceConfiguration config; diff --git a/onnxruntime/core/providers/webgpu/webgpu_pix_frame_generator.h b/onnxruntime/core/providers/webgpu/webgpu_pix_frame_generator.h index 52a7459a81eba..16d5420191dc1 100644 --- a/onnxruntime/core/providers/webgpu/webgpu_pix_frame_generator.h +++ b/onnxruntime/core/providers/webgpu/webgpu_pix_frame_generator.h @@ -14,7 +14,7 @@ #include -#include +#include "core/providers/webgpu/webgpu_external_header.h" namespace onnxruntime { @@ -41,7 +41,7 @@ namespace webgpu { // WebGpuContext destruction. class WebGpuPIXFrameGenerator { public: - WebGpuPIXFrameGenerator(wgpu::Instance instance, wgpu::Adapter adapter, wgpu::Device device); + WebGpuPIXFrameGenerator(wgpu::Instance instance, wgpu::Device device); ~WebGpuPIXFrameGenerator(); void GeneratePIXFrame(); diff --git a/onnxruntime/core/providers/webgpu/webgpu_provider_factory.cc b/onnxruntime/core/providers/webgpu/webgpu_provider_factory.cc index 60c61b2ca5665..d6812b2d0704d 100644 --- a/onnxruntime/core/providers/webgpu/webgpu_provider_factory.cc +++ b/onnxruntime/core/providers/webgpu/webgpu_provider_factory.cc @@ -143,14 +143,34 @@ std::shared_ptr WebGpuProviderFactoryCreator::Create( } } + std::string preserve_device_str; + bool preserve_device = false; + if (config_options.TryGetConfigEntry(kPreserveDevice, preserve_device_str)) { + if (preserve_device_str == kPreserveDevice_ON) { + preserve_device = true; + } else if (preserve_device_str == kPreserveDevice_OFF) { + preserve_device = false; + } else { + ORT_THROW("Invalid preserve device: ", preserve_device_str); + } + } + webgpu::WebGpuContextConfig context_config{ context_id, reinterpret_cast(webgpu_instance), reinterpret_cast(webgpu_device), reinterpret_cast(dawn_proc_table), validation_mode, + preserve_device, }; + LOGS_DEFAULT(VERBOSE) << "WebGPU EP Device ID: " << context_id; + LOGS_DEFAULT(VERBOSE) << "WebGPU EP WGPUInstance: " << webgpu_instance; + LOGS_DEFAULT(VERBOSE) << "WebGPU EP WGPUDevice: " << webgpu_device; + LOGS_DEFAULT(VERBOSE) << "WebGPU EP DawnProcTable: " << dawn_proc_table; + LOGS_DEFAULT(VERBOSE) << "WebGPU EP ValidationMode: " << validation_mode; + LOGS_DEFAULT(VERBOSE) << "WebGPU EP PreserveDevice: " << preserve_device; + // // STEP.3 - prepare parameters for WebGPU context initialization. // diff --git a/onnxruntime/core/providers/webgpu/webgpu_provider_options.h b/onnxruntime/core/providers/webgpu/webgpu_provider_options.h index 1cf316f4304e5..fcfd6774f8ab8 100644 --- a/onnxruntime/core/providers/webgpu/webgpu_provider_options.h +++ b/onnxruntime/core/providers/webgpu/webgpu_provider_options.h @@ -30,6 +30,8 @@ constexpr const char* kValidationMode = "WebGPU:validationMode"; constexpr const char* kForceCpuNodeNames = "WebGPU:forceCpuNodeNames"; constexpr const char* kEnablePIXCapture = "WebGPU:enablePIXCapture"; +constexpr const char* kPreserveDevice = "WebGPU:preserveDevice"; + // The following are the possible values for the provider options. constexpr const char* kDawnBackendType_D3D12 = "D3D12"; @@ -44,6 +46,9 @@ constexpr const char* kEnableGraphCapture_OFF = "0"; constexpr const char* kEnablePIXCapture_ON = "1"; constexpr const char* kEnablePIXCapture_OFF = "0"; +constexpr const char* kPreserveDevice_ON = "1"; +constexpr const char* kPreserveDevice_OFF = "0"; + constexpr const char* kBufferCacheMode_Disabled = "disabled"; constexpr const char* kBufferCacheMode_LazyRelease = "lazyRelease"; constexpr const char* kBufferCacheMode_Simple = "simple"; diff --git a/onnxruntime/core/providers/webgpu/webgpu_utils.cc b/onnxruntime/core/providers/webgpu/webgpu_utils.cc new file mode 100644 index 0000000000000..9b16767475c0c --- /dev/null +++ b/onnxruntime/core/providers/webgpu/webgpu_utils.cc @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +#include "core/providers/webgpu/webgpu_utils.h" +namespace onnxruntime { +namespace webgpu { + +TensorShape ReduceShapeByComponents(const TensorShape& shape, int64_t components) { + // Reduce the last dimensions by components creating a new tensor shape. + TensorShapeVector shape_vector = shape.AsShapeVector(); + auto reduce_index = shape_vector.size() - 1; + // Find the last dimension that is divisible by components. + while (shape_vector[reduce_index] % components != 0 && reduce_index > 0) { + ORT_ENFORCE(components % shape_vector[reduce_index] == 0, "The components must divide dims"); + components /= shape_vector[reduce_index]; + shape_vector[reduce_index] = 1; + reduce_index--; + } + ORT_ENFORCE(reduce_index >= 0 && shape_vector[reduce_index] % components == 0, "The last non-unit dimension of the input shape must be divisible by the number of components."); + shape_vector[reduce_index] /= components; + return TensorShape(shape_vector); +} + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webgpu/webgpu_utils.h b/onnxruntime/core/providers/webgpu/webgpu_utils.h new file mode 100644 index 0000000000000..e02d9266e8a0e --- /dev/null +++ b/onnxruntime/core/providers/webgpu/webgpu_utils.h @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include "core/common/common.h" +#include "core/framework/tensor_shape.h" + +namespace onnxruntime { +namespace webgpu { + +inline int GetMaxComponents(int64_t size) { + if (size % 4 == 0) { + return 4; + } else if (size % 2 == 0) { + return 2; + } + return 1; +} + +inline std::string SumVector(std::string x, int components) { + switch (components) { + case 1: + return x; + case 2: + return "(" + x + ".x + " + x + ".y" + ")"; + case 4: + return "(" + x + ".x + " + x + ".y + " + x + ".z + " + x + ".w" + ")"; + default: + ORT_THROW("Unsupported number of components: ", components); + } +} + +inline std::string MakeScalarOrVectorType(int components, std::string_view data_type) { + switch (components) { + case 1: + return std::string{data_type}; + case 2: + return MakeStringWithClassicLocale("vec2<", data_type, ">"); + case 3: + return MakeStringWithClassicLocale("vec3<", data_type, ">"); + case 4: + return MakeStringWithClassicLocale("vec4<", data_type, ">"); + default: + ORT_THROW("Unsupported number of components: ", components); + } +} + +TensorShape ReduceShapeByComponents(const TensorShape& shape, int64_t components); + +} // namespace webgpu +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/webnn/allocator.cc b/onnxruntime/core/providers/webnn/allocator.cc index 9c5cd651e1f00..8cf5b8cd72a5c 100644 --- a/onnxruntime/core/providers/webnn/allocator.cc +++ b/onnxruntime/core/providers/webnn/allocator.cc @@ -16,7 +16,7 @@ void* WebNNTensorAllocator::Alloc(size_t size) { // We don't need to transfer the tensor to an MLTensor, so we don't need to allocate an MLTensor id. return nullptr; } - void* p = EM_ASM_PTR({ return Module.jsepReserveTensorId(); }); + void* p = EM_ASM_PTR({ return Module.webnnReserveTensorId(); }); allocations_[p] = size; stats_.num_allocs++; stats_.bytes_in_use += SafeInt(size); @@ -27,7 +27,7 @@ void WebNNTensorAllocator::Free(void* p) { if (p == nullptr) { return; } - EM_ASM({ Module.jsepReleaseTensorId($0); }, p); + EM_ASM({ Module.webnnReleaseTensorId($0); }, p); size_t size = allocations_[p]; stats_.bytes_in_use -= size; allocations_.erase(p); diff --git a/onnxruntime/core/providers/webnn/builders/helper.cc b/onnxruntime/core/providers/webnn/builders/helper.cc index 20f3ffddd2779..e0d82b26c2174 100644 --- a/onnxruntime/core/providers/webnn/builders/helper.cc +++ b/onnxruntime/core/providers/webnn/builders/helper.cc @@ -58,12 +58,12 @@ bool GetShape(const NodeArg& node_arg, std::vector& shape, const loggin return true; } -bool IsNodeSupported(const Node& node, const GraphViewer& graph_viewer, const WebnnDeviceType device_type, +bool IsNodeSupported(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType device_type, const emscripten::val& wnn_limits, const logging::Logger& logger) { const auto& op_builders = GetOpBuilders(); if (Contains(op_builders, node.OpType())) { const auto* op_builder = op_builders.at(node.OpType()); - return op_builder->IsOpSupported(graph_viewer.GetAllInitializedTensors(), node, device_type, wnn_limits, logger); + return op_builder->IsOpSupported(graph_viewer, node, device_type, wnn_limits, logger); } else { return false; } @@ -107,7 +107,7 @@ std::unordered_set GetSupportedNodes(const GraphViewer& graph_viewe std::unordered_set supported_nodes; for (const auto& node : graph_viewer.Nodes()) { - const bool supported = IsNodeSupported(node, graph_viewer, device_type, wnn_limits, logger); + const bool supported = IsNodeSupported(graph_viewer, node, device_type, wnn_limits, logger); LOGS(logger, VERBOSE) << "Operator type: [" << node.OpType() << "] index: [" << node.Index() << "] name: [" << node.Name() @@ -144,9 +144,19 @@ bool IsSupportedDataType(const int32_t onnx_data_type, const emscripten::val& we const std::string_view webnn_data_type = it->second; // Check if WebNN supports the data type. - emscripten::val is_supported = - webnn_supported_data_types.call("includes", emscripten::val(std::string(webnn_data_type))); - return is_supported.as(); + bool is_supported = webnn_supported_data_types.call("includes", + emscripten::val(std::string(webnn_data_type))) + .as(); + + if (webnn_data_type == "int64" && + !is_supported && + webnn_supported_data_types.call("includes", emscripten::val("int32")).as()) { + // Current context doesn't support int64, but int32 is supported. + // We can use int32 as a workaround. + is_supported = true; + } + + return is_supported; } // Check if the input or output data type of ONNX node is supported by the WebNN operator. diff --git a/onnxruntime/core/providers/webnn/builders/helper.h b/onnxruntime/core/providers/webnn/builders/helper.h index 5513001f97545..95c4b79053a1f 100644 --- a/onnxruntime/core/providers/webnn/builders/helper.h +++ b/onnxruntime/core/providers/webnn/builders/helper.h @@ -82,13 +82,14 @@ inline std::string GetTensorName(const ConstPointerContainer index) ? std::string(input_defs[index]->Name()) : ""; } -inline std::vector GetVecUint32FromVecInt64(gsl::span int64_vec) { - std::vector uint32_vec; - uint32_vec.reserve(int64_vec.size()); +template +inline std::vector GetNarrowedIntfromInt64(gsl::span int64_vec) { + std::vector vec; + vec.reserve(int64_vec.size()); std::transform(int64_vec.begin(), int64_vec.end(), - std::back_inserter(uint32_vec), - [](int64_t val) -> uint32_t { return SafeInt(val); }); - return uint32_vec; + std::back_inserter(vec), + [](int64_t val) -> T { return SafeInt(val); }); + return vec; } template @@ -170,12 +171,13 @@ inline bool ReadScalarTensorData(const onnx::TensorProto& tensor, emscripten::va return true; } -inline bool IsEmptyTensor(const InitializedTensorSet& initializers, const std::string& name) { - if (name.empty() || !Contains(initializers, name)) { +inline bool IsEmptyTensor(const GraphViewer& graph_viewer, const std::string& name) { + const auto* tensor_init = graph_viewer.GetConstantInitializer(name); + if (name.empty() || !tensor_init) { return true; } - const auto& tensor = *initializers.at(name); + const auto& tensor = *tensor_init; const auto dims = tensor.dims(); // An empty tensor contains a 0 in the dimensions list. return std::any_of(dims.begin(), dims.end(), [](auto d) { return d == 0; }); diff --git a/onnxruntime/core/providers/webnn/builders/impl/argmax_min_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/argmax_min_op_builder.cc index d61ae1a1f6be7..fc630af8cf1e3 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/argmax_min_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/argmax_min_op_builder.cc @@ -20,7 +20,7 @@ class ArgMaxMinOpBuilder : public BaseOpBuilder { const logging::Logger& logger) const override ORT_MUST_USE_RESULT; // Operator support related. - bool IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, + bool IsOpSupportedImpl(const GraphViewer&, const Node& node, WebnnDeviceType device_type, const logging::Logger& logger) const override; }; @@ -43,16 +43,20 @@ Status ArgMaxMinOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, emscripten::val options = emscripten::val::object(); options.set("keepDimensions", keep_dims == 1); - // TODO(Honry): check whether int64 output data type is supported by WebNN opSupportLimits() API. - options.set("outputDataType", "int64"); + std::string output_data_type = "int64"; + if (!model_builder.IsInt64Supported()) { + // Int64 is not supported by current context, use int32 instead. + output_data_type = "int32"; + } + options.set("outputDataType", output_data_type); options.set("label", node.Name()); emscripten::val output = emscripten::val::object(); const auto& op_type = node.OpType(); if (op_type == "ArgMax") { - output = model_builder.GetBuilder().call("argMax", input, narrow(axis), options); + output = model_builder.GetBuilder().call("argMax", input, SafeInt(axis).Ref(), options); } else if (op_type == "ArgMin") { - output = model_builder.GetBuilder().call("argMin", input, narrow(axis), options); + output = model_builder.GetBuilder().call("argMin", input, SafeInt(axis).Ref(), options); } else { return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "ArgMaxMinOpBuilder, unknown op: ", op_type); } @@ -62,7 +66,7 @@ Status ArgMaxMinOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, } // Operator support related. -bool ArgMaxMinOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, +bool ArgMaxMinOpBuilder::IsOpSupportedImpl(const GraphViewer& /* initializers */, const Node& node, WebnnDeviceType device_type, const logging::Logger& logger) const { diff --git a/onnxruntime/core/providers/webnn/builders/impl/base_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/base_op_builder.cc index 4504a54a379f3..d5683454c89b7 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/base_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/base_op_builder.cc @@ -17,7 +17,7 @@ namespace webnn { Status BaseOpBuilder::AddToModelBuilder(ModelBuilder& model_builder, const Node& node, const logging::Logger& logger) const { ORT_RETURN_IF_NOT( - IsOpSupported(model_builder.GetInitializerTensors(), node, model_builder.GetWebnnDeviceType(), + IsOpSupported(model_builder.GetGraphViewer(), node, model_builder.GetWebnnDeviceType(), model_builder.GetOpSupportLimits(), logger), "Unsupported operator ", node.OpType()); ORT_RETURN_IF_ERROR(AddToModelBuilderImpl(model_builder, node, logger)); @@ -26,10 +26,10 @@ Status BaseOpBuilder::AddToModelBuilder(ModelBuilder& model_builder, const Node& // Operator support related. -bool BaseOpBuilder::IsOpSupported(const InitializedTensorSet& initializers, const Node& node, +bool BaseOpBuilder::IsOpSupported(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType device_type, const emscripten::val& wnn_limits, const logging::Logger& logger) const { - if (!HasSupportedInputs(initializers, node, wnn_limits, logger)) + if (!HasSupportedInputs(graph_viewer, node, wnn_limits, logger)) return false; if (!HasSupportedOutputs(node, wnn_limits, logger)) @@ -38,11 +38,11 @@ bool BaseOpBuilder::IsOpSupported(const InitializedTensorSet& initializers, cons if (!HasSupportedOpSet(node, logger)) return false; - return IsOpSupportedImpl(initializers, node, device_type, logger); + return IsOpSupportedImpl(graph_viewer, node, device_type, logger); } -bool BaseOpBuilder::HasSupportedInputs(const InitializedTensorSet& initializers, const Node& node, const emscripten::val& wnn_limits, - const logging::Logger& logger) const { +bool BaseOpBuilder::HasSupportedInputs(const GraphViewer& graph_viewer, const Node& node, + const emscripten::val& wnn_limits, const logging::Logger& logger) const { const auto node_name = MakeString("Node [", node.Name(), "] type [", node.OpType(), "]"); for (const auto* input : node.InputDefs()) { if (!IsTensorShapeSupported(*input, node_name, logger, allow_empty_tensor_as_input_)) { @@ -50,10 +50,10 @@ bool BaseOpBuilder::HasSupportedInputs(const InitializedTensorSet& initializers, } } - return HasSupportedInputsImpl(initializers, node, wnn_limits, logger); + return HasSupportedInputsImpl(graph_viewer, node, wnn_limits, logger); } -bool BaseOpBuilder::HasSupportedInputsImpl(const InitializedTensorSet& initializers, const Node& node, +bool BaseOpBuilder::HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const { // We only check the type of input 0 by default, specific op builder can override this. diff --git a/onnxruntime/core/providers/webnn/builders/impl/base_op_builder.h b/onnxruntime/core/providers/webnn/builders/impl/base_op_builder.h index 0a4367a71add4..b794ff6a63a6c 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/base_op_builder.h +++ b/onnxruntime/core/providers/webnn/builders/impl/base_op_builder.h @@ -30,17 +30,17 @@ class BaseOpBuilder : public IOpBuilder { // Operator support related. public: - bool IsOpSupported(const InitializedTensorSet& initializers, const Node& node, + bool IsOpSupported(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType device_type, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; protected: - virtual bool IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, const Node& /* node */, + virtual bool IsOpSupportedImpl(const GraphViewer& /* graph_viewer */, const Node& /* node */, const WebnnDeviceType /* device_type */, const logging::Logger& /* logger */) const { return true; } - virtual bool HasSupportedInputsImpl(const InitializedTensorSet& initializers, const Node& node, const emscripten::val& wnn_limits, + virtual bool HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const; virtual bool HasSupportedOutputsImpl(const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const; @@ -56,7 +56,7 @@ class BaseOpBuilder : public IOpBuilder { private: bool HasSupportedOpSet(const Node& node, const logging::Logger& logger) const; - bool HasSupportedInputs(const InitializedTensorSet& initializers, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const; + bool HasSupportedInputs(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const; bool HasSupportedOutputs(const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const; const bool allow_empty_tensor_as_input_; // Some operators can handle ignoring an empty tensor as input. diff --git a/onnxruntime/core/providers/webnn/builders/impl/binary_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/binary_op_builder.cc index c17ad0c89bd9d..29d02690d17c8 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/binary_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/binary_op_builder.cc @@ -20,7 +20,7 @@ class BinaryOpBuilder : public BaseOpBuilder { const logging::Logger& logger) const override ORT_MUST_USE_RESULT; // Operator support related. - bool HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; }; @@ -57,7 +57,7 @@ Status BinaryOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const return Status::OK(); } -bool BinaryOpBuilder::HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, +bool BinaryOpBuilder::HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const { const auto& input_defs = node.InputDefs(); const std::string_view op_type = node.OpType(); diff --git a/onnxruntime/core/providers/webnn/builders/impl/builder_utils.cc b/onnxruntime/core/providers/webnn/builders/impl/builder_utils.cc index 113cc3df5438d..63e2345243282 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/builder_utils.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/builder_utils.cc @@ -2,7 +2,6 @@ // Copyright (c) Intel Corporation. All rights reserved. // Licensed under the MIT License. -#include #include #include "core/providers/shared/utils/utils.h" diff --git a/onnxruntime/core/providers/webnn/builders/impl/cast_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/cast_op_builder.cc index 9eacc192d4c02..cd34dba52c066 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/cast_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/cast_op_builder.cc @@ -56,7 +56,8 @@ Status CastOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, operand_type = "int32"; break; case ONNX_NAMESPACE::TensorProto_DataType_INT64: - operand_type = "int64"; + // If int64 is not supported by current context, use int32 instead. + operand_type = model_builder.IsInt64Supported() ? "int64" : "int32"; break; case ONNX_NAMESPACE::TensorProto_DataType_UINT32: operand_type = "uint32"; diff --git a/onnxruntime/core/providers/webnn/builders/impl/clip_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/clip_op_builder.cc index a244efdd9b2eb..8e618285e29ba 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/clip_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/clip_op_builder.cc @@ -23,7 +23,7 @@ class ClipOpBuilder : public BaseOpBuilder { // Operator support related. private: - bool IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, + bool IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType device_type, const logging::Logger& logger) const override; }; @@ -61,15 +61,12 @@ Status ClipOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, // Operator support related. -bool ClipOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, +bool ClipOpBuilder::IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType device_type, const logging::Logger& logger) const { - // TODO: Update IsOpSupportedImpl to pass GraphViewer instead of InitializedTensorSet so the implementations - // can ensure initializers are constant. See #19401 for details of how this update was made to the NNAPI EP. - // GetClipMinMax(graph_viewer, node, minValue, maxValue, logger) float min, max; - return GetClipMinMax(initializers, node, min, max, logger); + return GetClipMinMax(graph_viewer, node, min, max, logger); } void CreateClipOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations) { diff --git a/onnxruntime/core/providers/webnn/builders/impl/concat_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/concat_op_builder.cc index 1bbe56ef9b477..f5b78bf4bc16b 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/concat_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/concat_op_builder.cc @@ -2,7 +2,6 @@ // Copyright (c) Intel Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/common/safeint.h" #include "core/providers/common.h" #include "core/providers/shared/utils/utils.h" #include "core/providers/webnn/builders/helper.h" @@ -21,7 +20,7 @@ class ConcatOpBuilder : public BaseOpBuilder { const logging::Logger& logger) const override ORT_MUST_USE_RESULT; // Operator support related. - bool HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; }; @@ -55,7 +54,7 @@ Status ConcatOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, return Status::OK(); } -bool ConcatOpBuilder::HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, +bool ConcatOpBuilder::HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const { const auto& input_defs = node.InputDefs(); const std::string_view op_type = node.OpType(); diff --git a/onnxruntime/core/providers/webnn/builders/impl/conv_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/conv_op_builder.cc index 043324ba49431..436324e087321 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/conv_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/conv_op_builder.cc @@ -2,7 +2,6 @@ // Copyright (c) Intel Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/common/safeint.h" #include "core/optimizer/initializer.h" #include "core/providers/common.h" #include "core/providers/shared/utils/utils.h" @@ -27,9 +26,9 @@ class ConvOpBuilder : public BaseOpBuilder { // Operator support related. private: - bool IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, + bool IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType device_type, const logging::Logger& logger) const override; - bool HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; }; @@ -76,7 +75,7 @@ common::Status SetConvBaseOptions(ModelBuilder& model_builder, if (output_padding.size() == 1 && is_conv1d) { output_padding.push_back(0); } - options.set("outputPadding", emscripten::val::array(GetVecUint32FromVecInt64(output_padding))); + options.set("outputPadding", emscripten::val::array(GetNarrowedIntfromInt64(output_padding))); // If output shape is explicitly provided, compute the pads. // Otherwise compute the output shape, as well as the pads if the auto_pad attribute is SAME_UPPER/SAME_LOWER. @@ -85,7 +84,7 @@ common::Status SetConvBaseOptions(ModelBuilder& model_builder, auto_pad_type, pads_out, output_shape, !is_nhwc)); if (output_shape[0] != -1 && output_shape[1] != -1) { - options.set("outputSizes", emscripten::val::array(GetVecUint32FromVecInt64(output_shape))); + options.set("outputSizes", emscripten::val::array(GetNarrowedIntfromInt64(output_shape))); } pads = pads_out; } else { @@ -95,13 +94,13 @@ common::Status SetConvBaseOptions(ModelBuilder& model_builder, const auto group = helper.Get("group", static_cast(1)); options.set("groups", group); - options.set("strides", emscripten::val::array(GetVecUint32FromVecInt64(strides))); - options.set("dilations", emscripten::val::array(GetVecUint32FromVecInt64(dilations))); + options.set("strides", emscripten::val::array(GetNarrowedIntfromInt64(strides))); + options.set("dilations", emscripten::val::array(GetNarrowedIntfromInt64(dilations))); // Permute the ONNX's pads, which is [beginning_height, beginning_width, ending_height, ending_width], // while WebNN's padding is [beginning_height, ending_height, beginning_width, ending_width]. const std::vector padding{pads[0], pads[2], pads[1], pads[3]}; - options.set("padding", emscripten::val::array(GetVecUint32FromVecInt64(padding))); + options.set("padding", emscripten::val::array(GetNarrowedIntfromInt64(padding))); // Add bias if present. if (input_defs.size() > 2) { @@ -120,7 +119,8 @@ Status AddInitializerInNewLayout(ModelBuilder& model_builder, auto data_type = tensor.data_type(); const auto& shape = tensor.dims(); - std::vector dims = GetVecUint32FromVecInt64(std::vector(std::begin(shape), std::end(shape))); + std::vector dims = + GetNarrowedIntfromInt64(std::vector(std::begin(shape), std::end(shape))); if (is_conv1d) { // Support conv1d by prepending a 1 size dimension. @@ -229,7 +229,7 @@ Status ConvOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const N } else { input_shape.push_back(1); } - std::vector new_shape = GetVecUint32FromVecInt64(input_shape); + std::vector new_shape = GetNarrowedIntfromInt64(input_shape); input = model_builder.GetBuilder().call("reshape", input, emscripten::val::array(new_shape)); weight_shape.resize(4, 1); // Ensure 4D by appending 1's if needed. @@ -276,7 +276,7 @@ Status ConvOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const N // Reshape weight to 4D for conv1d. if (!is_nhwc || !is_constant_weight) { // The weight_shape has been appended 1's, reshape weight operand. - std::vector new_shape = GetVecUint32FromVecInt64(weight_shape); + std::vector new_shape = GetNarrowedIntfromInt64(weight_shape); emscripten::val reshape_options = emscripten::val::object(); reshape_options.set("label", node.Name() + "_reshape_filter"); filter = model_builder.GetBuilder().call("reshape", @@ -329,7 +329,7 @@ Status ConvOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const N const auto& output_defs = node.OutputDefs(); std::vector output_shape; ORT_RETURN_IF_NOT(GetShape(*output_defs[0], output_shape, logger), "Cannot get output shape"); - std::vector new_shape = GetVecUint32FromVecInt64(output_shape); + std::vector new_shape = GetNarrowedIntfromInt64(output_shape); emscripten::val reshape_options = emscripten::val::object(); reshape_options.set("label", node.Name() + "_reshape_output"); output = model_builder.GetBuilder().call("reshape", @@ -344,7 +344,7 @@ Status ConvOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const N // Operator support related. -bool ConvOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, +bool ConvOpBuilder::IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType device_type, const logging::Logger& logger) const { @@ -381,7 +381,7 @@ bool ConvOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, return true; } -bool ConvOpBuilder::HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, +bool ConvOpBuilder::HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const { const auto& input_defs = node.InputDefs(); const std::string_view op_type = node.OpType(); diff --git a/onnxruntime/core/providers/webnn/builders/impl/cumsum_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/cumsum_op_builder.cc index be30c5520d62e..14324415b3659 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/cumsum_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/cumsum_op_builder.cc @@ -2,7 +2,6 @@ // Copyright (c) Intel Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/common/safeint.h" #include "core/framework/tensorprotoutils.h" #include "core/optimizer/initializer.h" #include "core/providers/common.h" @@ -28,7 +27,7 @@ class CumSumOpBuilder : public BaseOpBuilder { // Operator support related. private: - bool IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, + bool IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; }; @@ -64,14 +63,14 @@ Status CumSumOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const options.set("label", node.Name()); emscripten::val output = emscripten::val::object(); - output = model_builder.GetBuilder().call("cumulativeSum", input, gsl::narrow(webnn_axis), - options); + output = model_builder.GetBuilder().call("cumulativeSum", input, + SafeInt(webnn_axis).Ref(), options); model_builder.AddOperand(node.OutputDefs()[0]->Name(), std::move(output)); return Status::OK(); } // Operator support related. -bool CumSumOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, +bool CumSumOpBuilder::IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, WebnnDeviceType /* device_type */, const logging::Logger& logger) const { @@ -83,7 +82,8 @@ bool CumSumOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers const std::string axis_name = GetTensorName(input_defs, 1); // Inputs contain optional 'axis' input. - if (!Contains(initializers, axis_name)) { + const auto* init = graph_viewer.GetConstantInitializer(axis_name); + if (init == nullptr) { LOGS(logger, VERBOSE) << "The axis must be a constant initializer."; return false; } diff --git a/onnxruntime/core/providers/webnn/builders/impl/dropout_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/dropout_op_builder.cc index 9bb930c63b009..c22dd9e97bb1a 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/dropout_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/dropout_op_builder.cc @@ -24,7 +24,7 @@ class DropoutOpBuilder : public BaseOpBuilder { // Operator support related. private: - bool IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, + bool IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; }; @@ -58,7 +58,7 @@ Status DropoutOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, if (output_defs.size() > 1) { std::vector mask_shape; ORT_RETURN_IF_NOT(GetShape(*output_defs[1], mask_shape, logger), "Cannot get mask output's shape"); - std::vector dims = GetVecUint32FromVecInt64(mask_shape); + std::vector dims = GetNarrowedIntfromInt64(mask_shape); emscripten::val one_constant = model_builder.CreateOrGetConstant( ONNX_NAMESPACE::TensorProto_DataType_BOOL, 1, dims); @@ -73,7 +73,7 @@ Status DropoutOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, } // Operator support related. -bool DropoutOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, +bool DropoutOpBuilder::IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { diff --git a/onnxruntime/core/providers/webnn/builders/impl/dynamicQuantizeLinear_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/dynamicQuantizeLinear_op_builder.cc index 55746bb1f61f0..f3363b1e186d5 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/dynamicQuantizeLinear_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/dynamicQuantizeLinear_op_builder.cc @@ -2,7 +2,6 @@ // Copyright (c) Intel Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/common/safeint.h" #include "core/optimizer/initializer.h" #include "core/providers/common.h" #include "core/providers/shared/utils/utils.h" diff --git a/onnxruntime/core/providers/webnn/builders/impl/einsum_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/einsum_op_builder.cc index 1f51e26fecfa5..e5b4fcddc4221 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/einsum_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/einsum_op_builder.cc @@ -2,7 +2,6 @@ // Copyright (c) Intel Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/common/safeint.h" #include "core/framework/tensorprotoutils.h" #include "core/optimizer/initializer.h" #include "core/providers/common.h" @@ -25,9 +24,9 @@ class EinsumOpBuilder : public BaseOpBuilder { const logging::Logger& logger) const override ORT_MUST_USE_RESULT; // Operator support related. - bool IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; - bool HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; }; @@ -695,7 +694,7 @@ Status EinsumOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, // Operator support related. -bool EinsumOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, +bool EinsumOpBuilder::IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType device_type, const logging::Logger& logger) const { @@ -735,7 +734,7 @@ bool EinsumOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* initializ return true; } -bool EinsumOpBuilder::HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, +bool EinsumOpBuilder::HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const { const auto& input_defs = node.InputDefs(); diff --git a/onnxruntime/core/providers/webnn/builders/impl/expand_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/expand_op_builder.cc index f5e1f59602c5d..2c28786b788f9 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/expand_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/expand_op_builder.cc @@ -2,7 +2,6 @@ // Copyright (c) Intel Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/common/safeint.h" #include "core/framework/tensorprotoutils.h" #include "core/optimizer/initializer.h" #include "core/providers/common.h" @@ -28,7 +27,7 @@ class ExpandOpBuilder : public BaseOpBuilder { // Operator support related. private: - bool IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, + bool IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; }; @@ -56,34 +55,35 @@ Status ExpandOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, emscripten::val options = emscripten::val::object(); options.set("label", node.Name()); - emscripten::val output = - model_builder.GetBuilder().call("expand", - input, - emscripten::val::array(GetVecUint32FromVecInt64(output_shape)), - options); + emscripten::val output_shape_arr = emscripten::val::array(GetNarrowedIntfromInt64(output_shape)); + emscripten::val output = model_builder.GetBuilder().call("expand", input, output_shape_arr, options); model_builder.AddOperand(node.OutputDefs()[0]->Name(), std::move(output)); return Status::OK(); } // Operator support related. -bool ExpandOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, +bool ExpandOpBuilder::IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { const auto& input_defs = node.InputDefs(); const auto& shape_name = input_defs[1]->Name(); - if (!Contains(initializers, shape_name)) { + + // We need a constant which can not be overriden by input + const auto* shape_init = graph_viewer.GetConstantInitializer(shape_name); + if (!shape_init) { LOGS(logger, VERBOSE) << "The shape must be a constant initializer."; return false; } - std::vector new_shape; - const auto& shape_tensor = *initializers.at(shape_name); + const auto& shape_tensor = *shape_init; if (shape_tensor.data_type() != ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64) { LOGS(logger, VERBOSE) << "The type of tensor's element data must be INT64."; return false; } + + std::vector new_shape; if (!ReadIntArrayFrom1DTensor(shape_tensor, new_shape, logger)) { LOGS(logger, VERBOSE) << "Cannot get shape."; return false; diff --git a/onnxruntime/core/providers/webnn/builders/impl/flatten_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/flatten_op_builder.cc index d0ece026a7048..c4ff280b95b6e 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/flatten_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/flatten_op_builder.cc @@ -2,7 +2,6 @@ // Copyright (c) Intel Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/common/safeint.h" #include "core/providers/common.h" #include "core/providers/shared/utils/utils.h" #include "core/providers/webnn/builders/helper.h" diff --git a/onnxruntime/core/providers/webnn/builders/impl/gatherElements_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/gatherElements_op_builder.cc index 1db0ec12b0dfb..06beb56415609 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/gatherElements_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/gatherElements_op_builder.cc @@ -20,7 +20,7 @@ class GatherElementsOpBuilder : public BaseOpBuilder { const logging::Logger& logger) const override ORT_MUST_USE_RESULT; // Operator support related. - bool HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; }; @@ -49,7 +49,7 @@ Status GatherElementsOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builde // Operator support related. -bool GatherElementsOpBuilder::HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, +bool GatherElementsOpBuilder::HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const { const auto& data = *node.InputDefs()[0]; diff --git a/onnxruntime/core/providers/webnn/builders/impl/gatherND_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/gatherND_op_builder.cc index 279305c8ed3b4..9200c596c0e53 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/gatherND_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/gatherND_op_builder.cc @@ -20,9 +20,9 @@ class GatherNDOpBuilder : public BaseOpBuilder { const logging::Logger& logger) const override ORT_MUST_USE_RESULT; // Operator support related. - bool IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; - bool HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; }; @@ -43,7 +43,7 @@ Status GatherNDOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, con // Operator support related. -bool GatherNDOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, const Node& node, +bool GatherNDOpBuilder::IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { NodeAttrHelper helper(node); @@ -55,7 +55,7 @@ bool GatherNDOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* initial return true; } -bool GatherNDOpBuilder::HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, +bool GatherNDOpBuilder::HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const { const auto& data = *node.InputDefs()[0]; const auto& indices = *node.InputDefs()[1]; diff --git a/onnxruntime/core/providers/webnn/builders/impl/gather_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/gather_op_builder.cc index 4d983eeb799fd..d84c70032e1d1 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/gather_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/gather_op_builder.cc @@ -20,9 +20,9 @@ class GatherOpBuilder : public BaseOpBuilder { const logging::Logger& logger) const override ORT_MUST_USE_RESULT; // Operator support related. - bool IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; - bool HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; }; @@ -51,7 +51,7 @@ Status GatherOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, // Operator support related. -bool GatherOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, +bool GatherOpBuilder::IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { @@ -69,7 +69,7 @@ bool GatherOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* initializ return true; } -bool GatherOpBuilder::HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, +bool GatherOpBuilder::HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const { const auto& input = *node.InputDefs()[0]; const auto& indices = *node.InputDefs()[1]; diff --git a/onnxruntime/core/providers/webnn/builders/impl/gemm_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/gemm_op_builder.cc index 49c03e5af23b4..fbf3ac1df2bc2 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/gemm_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/gemm_op_builder.cc @@ -2,7 +2,6 @@ // Copyright (c) Intel Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/common/safeint.h" #include "core/providers/common.h" #include "core/providers/shared/utils/utils.h" #include "core/providers/webnn/builders/helper.h" @@ -23,9 +22,9 @@ class GemmOpBuilder : public BaseOpBuilder { // Operator support related. private: - bool IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; - bool HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; }; @@ -55,22 +54,20 @@ Status GemmOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const N if (a_shape.size() == 1) { extended_a_shape = true; a_shape.insert(a_shape.begin(), 1); + emscripten::val a_shape_arr = emscripten::val::array(GetNarrowedIntfromInt64(a_shape)); emscripten::val reshape_a_options = emscripten::val::object(); reshape_a_options.set("label", node.Name() + "_reshape_a"); - a = model_builder.GetBuilder().call("reshape", a, - emscripten::val::array(GetVecUint32FromVecInt64(a_shape)), - reshape_a_options); + a = model_builder.GetBuilder().call("reshape", a, a_shape_arr, reshape_a_options); } // If the second argument is 1-D, it is promoted to a matrix by appending a 1 to its dimensions. bool extended_b_shape = false; if (b_shape.size() == 1) { extended_b_shape = true; b_shape.push_back(1); + emscripten::val b_shape_arr = emscripten::val::array(GetNarrowedIntfromInt64(b_shape)); emscripten::val reshape_b_options = emscripten::val::object(); reshape_b_options.set("label", node.Name() + "_reshape_b"); - b = model_builder.GetBuilder().call("reshape", b, - emscripten::val::array(GetVecUint32FromVecInt64(b_shape)), - reshape_b_options); + b = model_builder.GetBuilder().call("reshape", b, b_shape_arr, reshape_b_options); } output = model_builder.GetBuilder().call("matmul", a, b, options); @@ -88,9 +85,9 @@ Status GemmOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const N else if (extended_a_shape) { std::vector new_shape; for (size_t i = 0; i < b_shape.size() - 2; i++) { - new_shape.push_back(narrow(b_shape[i])); + new_shape.push_back(SafeInt(b_shape[i])); } - new_shape.push_back(narrow(b_shape.back())); + new_shape.push_back(SafeInt(b_shape.back())); output = model_builder.GetBuilder().call("reshape", output, emscripten::val::array(new_shape), @@ -100,7 +97,7 @@ Status GemmOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const N else if (extended_b_shape) { std::vector new_shape; for (size_t i = 0; i < a_shape.size() - 1; i++) { - new_shape.push_back(narrow(a_shape[i])); + new_shape.push_back(SafeInt(a_shape[i])); } output = model_builder.GetBuilder().call("reshape", output, @@ -151,7 +148,7 @@ Status GemmOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const N // Operator support related. -bool GemmOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, +bool GemmOpBuilder::IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { @@ -215,7 +212,7 @@ bool GemmOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* initializer return true; } -bool GemmOpBuilder::HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, +bool GemmOpBuilder::HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const { const auto& input_defs = node.InputDefs(); const std::string_view op_type = node.OpType(); diff --git a/onnxruntime/core/providers/webnn/builders/impl/gru_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/gru_op_builder.cc index 1180721105fb0..403bc8af8ac1f 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/gru_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/gru_op_builder.cc @@ -24,9 +24,9 @@ class GruOpBuilder : public BaseOpBuilder { // Operator support related. private: - bool IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, + bool IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /*device_type*/, const logging::Logger& logger) const override; - bool HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool HasSupportedInputsImpl(const GraphViewer& graph_viewer, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; bool HasSupportedOutputsImpl(const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; @@ -119,7 +119,7 @@ Status GruOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const No return Status::OK(); } -bool GruOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, +bool GruOpBuilder::IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /*device_type*/, const logging::Logger& logger) const { const auto& input_defs = node.InputDefs(); if (input_defs.size() < 3) { @@ -135,12 +135,13 @@ bool GruOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, c int32_t steps = static_cast(input_shape[0]); if (TensorExists(input_defs, 4)) { - if (!Contains(initializers, input_defs[4]->Name())) { + const auto* seq_initializer = graph_viewer.GetConstantInitializer(input_defs[4]->Name()); + if (!seq_initializer) { LOGS(logger, ERROR) << "GRU: sequence_lens must be constant"; return false; } - const auto& sequence_lens_tensor = *initializers.at(input_defs[4]->Name()); + const auto& sequence_lens_tensor = *seq_initializer; std::vector sequence_lens; if (!ReadIntArrayFrom1DTensor(sequence_lens_tensor, sequence_lens, logger)) { LOGS(logger, ERROR) << "Cannot read sequence lens tensor"; @@ -187,7 +188,7 @@ bool GruOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, c return true; } -bool GruOpBuilder::HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, +bool GruOpBuilder::HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const { const auto& input_defs = node.InputDefs(); const std::string_view op_type = node.OpType(); diff --git a/onnxruntime/core/providers/webnn/builders/impl/logical_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/logical_op_builder.cc index 86fc1bc01e18a..7c6de428d0934 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/logical_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/logical_op_builder.cc @@ -19,9 +19,9 @@ class LogicalOpBuilder : public BaseOpBuilder { Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, const logging::Logger& logger) const override ORT_MUST_USE_RESULT; // Operator support related. - bool IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; - bool HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; }; @@ -54,7 +54,7 @@ Status LogicalOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, cons return Status::OK(); } -bool LogicalOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, +bool LogicalOpBuilder::IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { @@ -72,7 +72,7 @@ bool LogicalOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* initiali return true; } -bool LogicalOpBuilder::HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, +bool LogicalOpBuilder::HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const { const auto& input_defs = node.InputDefs(); const std::string_view op_type = node.OpType(); diff --git a/onnxruntime/core/providers/webnn/builders/impl/lrn_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/lrn_op_builder.cc index 19c17f58bdb23..2e5d3d6b5228a 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/lrn_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/lrn_op_builder.cc @@ -21,9 +21,9 @@ class LRNOpBuilder : public BaseOpBuilder { // Operator support related. private: - bool IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, + bool IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; - bool HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; bool HasSupportedOutputsImpl(const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; @@ -128,7 +128,7 @@ Status LRNOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, } // Operator support related. -bool LRNOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, +bool LRNOpBuilder::IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { @@ -146,7 +146,7 @@ bool LRNOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, return true; } -bool LRNOpBuilder::HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, +bool LRNOpBuilder::HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const { const auto& input_defs = node.InputDefs(); const std::string_view op_type = node.OpType(); diff --git a/onnxruntime/core/providers/webnn/builders/impl/lstm_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/lstm_op_builder.cc index b25037d439bf4..c49f360c11737 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/lstm_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/lstm_op_builder.cc @@ -23,9 +23,9 @@ class LstmOpBuilder : public BaseOpBuilder { // Operator support related. private: - bool IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, + bool IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /*device_type*/, const logging::Logger& logger) const override; - bool HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; bool HasSupportedOutputsImpl(const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; @@ -125,7 +125,7 @@ Status LstmOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const N return Status::OK(); } -bool LstmOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, +bool LstmOpBuilder::IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /*device_type*/, const logging::Logger& logger) const { const auto& input_defs = node.InputDefs(); if (input_defs.size() < 3) { @@ -141,12 +141,13 @@ bool LstmOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, int32_t steps = static_cast(input_shape[0]); if (TensorExists(input_defs, 4)) { - if (!Contains(initializers, input_defs[4]->Name())) { + const auto* sequence_lens_init = graph_viewer.GetConstantInitializer(input_defs[4]->Name()); + if (!sequence_lens_init) { LOGS(logger, ERROR) << "LSTM: sequence_lens must be constant"; return false; } - const auto& sequence_lens_tensor = *initializers.at(input_defs[4]->Name()); + const auto& sequence_lens_tensor = *sequence_lens_init; std::vector sequence_lens; if (!ReadIntArrayFrom1DTensor(sequence_lens_tensor, sequence_lens, logger)) { LOGS(logger, ERROR) << "Cannot read sequence lens tensor"; @@ -198,7 +199,7 @@ bool LstmOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, return true; } -bool LstmOpBuilder::HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, +bool LstmOpBuilder::HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const { const auto& input_defs = node.InputDefs(); const std::string_view op_type = node.OpType(); diff --git a/onnxruntime/core/providers/webnn/builders/impl/max_min_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/max_min_op_builder.cc index a7bcbfeb4b13e..7ec4ff640132c 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/max_min_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/max_min_op_builder.cc @@ -20,9 +20,9 @@ class MaxMinOpBuilder : public BaseOpBuilder { const logging::Logger& logger) const override ORT_MUST_USE_RESULT; // Operator support related. - bool IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, + bool IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; - bool HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; }; @@ -68,7 +68,7 @@ Status MaxMinOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, } // Operator support related. -bool MaxMinOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, +bool MaxMinOpBuilder::IsOpSupportedImpl(const GraphViewer&, const Node& node, WebnnDeviceType /* device_type */, const logging::Logger& logger) const { @@ -87,7 +87,7 @@ bool MaxMinOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* initializ return true; } -bool MaxMinOpBuilder::HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, +bool MaxMinOpBuilder::HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const { const auto& input_defs = node.InputDefs(); const std::string_view op_type = node.OpType(); diff --git a/onnxruntime/core/providers/webnn/builders/impl/normalization_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/normalization_op_builder.cc index 356f1a9042555..704c6a65624d8 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/normalization_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/normalization_op_builder.cc @@ -2,7 +2,6 @@ // Copyright (c) Intel Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/common/safeint.h" #include "core/optimizer/initializer.h" #include "core/providers/common.h" #include "core/providers/shared/utils/utils.h" @@ -23,9 +22,9 @@ class NormalizationOpBuilder : public BaseOpBuilder { // Operator support related. private: - bool IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, + bool IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; - bool HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; bool HasSupportedOutputsImpl(const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; @@ -208,7 +207,7 @@ Status NormalizationOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder output = model_builder.GetBuilder().call("instanceNormalization", input, options); // Reshape back to the original output shape for 3D input. if (input_shape.size() != 4) { - std::vector output_shape = GetVecUint32FromVecInt64(input_shape); + std::vector output_shape = GetNarrowedIntfromInt64(input_shape); emscripten::val reshape_output_options = emscripten::val::object(); reshape_output_options.set("label", node.Name() + "reshape_output"); output = model_builder.GetBuilder().call("reshape", @@ -226,7 +225,7 @@ Status NormalizationOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder // Operator support related. -bool NormalizationOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, +bool NormalizationOpBuilder::IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { @@ -271,7 +270,7 @@ bool NormalizationOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initi return true; } -bool NormalizationOpBuilder::HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, +bool NormalizationOpBuilder::HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const { const auto& input_defs = node.InputDefs(); diff --git a/onnxruntime/core/providers/webnn/builders/impl/pad_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/pad_op_builder.cc index d8373a45e4423..f17d87d41f9ae 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/pad_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/pad_op_builder.cc @@ -2,7 +2,6 @@ // Copyright (c) Intel Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/common/safeint.h" #include "core/providers/common.h" #include "core/providers/shared/utils/utils.h" #include "core/providers/webnn/builders/helper.h" @@ -26,7 +25,7 @@ class PadOpBuilder : public BaseOpBuilder { // Operator support related. private: - bool IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; }; @@ -156,7 +155,7 @@ Status PadOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, } // Operator support related. -bool PadOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, +bool PadOpBuilder::IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { @@ -184,7 +183,7 @@ bool PadOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, for (size_t i = 1; i < input_defs.size(); i++) { // Optional tensors (constant_value, axes) can be indicated by an empty name, just ignore it. const std::string input_name = GetTensorName(input_defs, i); - if (!input_name.empty() && !Contains(initializers, input_name)) { + if (!input_name.empty() && !graph_viewer.GetConstantInitializer(input_name)) { LOGS(logger, VERBOSE) << "Input [" << input_name << "] must be known as initializer"; return false; } diff --git a/onnxruntime/core/providers/webnn/builders/impl/pool_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/pool_op_builder.cc index 0af62dacedbd5..2d263c1ec1f9f 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/pool_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/pool_op_builder.cc @@ -2,7 +2,6 @@ // Copyright (c) Intel Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/common/safeint.h" #include "core/providers/common.h" #include "core/providers/shared/utils/utils.h" #include "core/providers/webnn/builders/helper.h" @@ -23,7 +22,7 @@ class PoolOpBuilder : public BaseOpBuilder { // Operator support related. private: - bool IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; }; @@ -95,7 +94,7 @@ Status PoolOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, auto_pad_type, pads_out, model_builder.GetPreferredLayout() == DataLayout::NCHW)); - pads = GetVecUint32FromVecInt64(pads_out); + pads = GetNarrowedIntfromInt64(pads_out); } // Permute the ONNX's pads, which is [beginning_height, beginning_width, ending_height, ending_width], // while WebNN's padding is [beginning_height, ending_height, beginning_width, ending_width]. @@ -112,7 +111,7 @@ Status PoolOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, } // Operator support related. -bool PoolOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, +bool PoolOpBuilder::IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { diff --git a/onnxruntime/core/providers/webnn/builders/impl/qdq_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/qdq_op_builder.cc index fddfb28184ada..dd25fb9bf9315 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/qdq_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/qdq_op_builder.cc @@ -2,7 +2,6 @@ // Copyright (c) Intel Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/common/safeint.h" #include "core/optimizer/initializer.h" #include "core/providers/common.h" #include "core/providers/shared/utils/utils.h" @@ -22,9 +21,9 @@ class QDQOpBuilder : public BaseOpBuilder { const logging::Logger& logger) const override ORT_MUST_USE_RESULT; // Operator support related. - bool IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; - bool HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; }; @@ -100,7 +99,7 @@ Status QDQOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, if (!has_zero_point) { if (zero_point_shape.empty()) { // zero_point has the same shape as the scale tensor. - zero_point_shape = GetVecUint32FromVecInt64(scale_shape); + zero_point_shape = GetNarrowedIntfromInt64(scale_shape); } // Create a zero constant with the same shape as the scale tensor. // The zero value has been pre-processed in the CreateOrGetConstant function, @@ -122,7 +121,7 @@ Status QDQOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, } // Operator support related. -bool QDQOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, +bool QDQOpBuilder::IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { @@ -153,7 +152,7 @@ bool QDQOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* initializers return true; } -bool QDQOpBuilder::HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, +bool QDQOpBuilder::HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const { const auto& input_defs = node.InputDefs(); const std::string_view op_type = node.OpType(); diff --git a/onnxruntime/core/providers/webnn/builders/impl/reduction_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/reduction_op_builder.cc index 93ad933d71c34..a3a0397eda4a3 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/reduction_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/reduction_op_builder.cc @@ -2,7 +2,6 @@ // Copyright (c) Intel Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/common/safeint.h" #include "core/providers/common.h" #include "core/providers/shared/utils/utils.h" #include "core/providers/webnn/builders/helper.h" @@ -29,7 +28,7 @@ class ReductionOpBuilder : public BaseOpBuilder { // Operator support related. private: - bool IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; }; @@ -124,7 +123,7 @@ Status ReductionOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, } // Operator support related. -bool ReductionOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, +bool ReductionOpBuilder::IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { @@ -137,7 +136,7 @@ bool ReductionOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializ const auto& op_type = node.OpType(); const std::string axes_name = GetTensorName(input_defs, 1); // If the optional input 'axes' is provided, it must be an initializer. - if (!axes_name.empty() && !Contains(initializers, axes_name)) { + if (!axes_name.empty() && !graph_viewer.GetConstantInitializer(axes_name)) { LOGS(logger, VERBOSE) << "Input axes of " << op_type << " must be a constant"; return false; } diff --git a/onnxruntime/core/providers/webnn/builders/impl/reshape_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/reshape_op_builder.cc index 0a438e98ad737..da5e034c38c8e 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/reshape_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/reshape_op_builder.cc @@ -2,7 +2,6 @@ // Copyright (c) Intel Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/common/safeint.h" #include "core/framework/tensorprotoutils.h" #include "core/optimizer/initializer.h" #include "core/providers/common.h" @@ -28,7 +27,7 @@ class ReshapeOpBuilder : public BaseOpBuilder { // Operator support related. private: - bool IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, + bool IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; }; @@ -75,7 +74,7 @@ Status ReshapeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, // Operator support related. -bool ReshapeOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, +bool ReshapeOpBuilder::IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { @@ -86,12 +85,13 @@ bool ReshapeOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializer return false; const auto& perm_name = input_defs[1]->Name(); - if (!Contains(initializers, perm_name)) { + const auto* perm_init = graph_viewer.GetConstantInitializer(perm_name); + if (!perm_init) { LOGS(logger, VERBOSE) << "New shape of reshape must be a constant initializer"; return false; } - const auto& perm_tensor = *initializers.at(perm_name); + const auto& perm_tensor = *perm_init; std::vector unpacked_tensor; auto status = onnxruntime::utils::UnpackInitializerData(perm_tensor, unpacked_tensor); if (!status.IsOK()) { diff --git a/onnxruntime/core/providers/webnn/builders/impl/resize_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/resize_op_builder.cc index 00f8cff25ccf5..f71ec2f98d112 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/resize_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/resize_op_builder.cc @@ -4,7 +4,6 @@ #include -#include "core/common/safeint.h" #include "core/providers/common.h" #include "core/framework/tensorprotoutils.h" #include "core/providers/webnn/builders/helper.h" @@ -31,7 +30,7 @@ class ResizeOpBuilder : public BaseOpBuilder { // Operator support related. private: - bool IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, + bool IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; // Resize opset 10- is very different than Resize opset 11+, with many key attributes missing. @@ -40,7 +39,7 @@ class ResizeOpBuilder : public BaseOpBuilder { }; // Helper functions -bool GetResizeScalesAndAxes(const InitializedTensorSet& initializers, +bool GetResizeScalesAndAxes(const GraphViewer& graph_viewer, const Node& node, std::vector& scales, std::vector& axes, const bool is_nhwc, const logging::Logger& logger) { @@ -49,13 +48,14 @@ bool GetResizeScalesAndAxes(const InitializedTensorSet& initializers, return false; const bool has_axes = !axes.empty(); - const auto& scales_tensor = *initializers.at(input_defs[2]->Name()); - if (scales_tensor.dims_size() != 1) { - LOGS(logger, ERROR) << "'scales' should be a 1D tensor."; + const auto* scales_init = graph_viewer.GetConstantInitializer(input_defs[2]->Name()); + if (!scales_init || scales_init->dims_size() != 1) { + LOGS(logger, ERROR) << "Expecting 'scales' as a 1D constant initialized tensor."; return false; } // Number of elements of 'scales' tensor. + const auto& scales_tensor = *scales_init; const auto num_of_scales = scales_tensor.dims()[0]; if (has_axes && num_of_scales != 2) { @@ -107,7 +107,7 @@ bool GetResizeScalesAndAxes(const InitializedTensorSet& initializers, return true; } -bool GetResizeSizesAndAxes(const InitializedTensorSet& initializers, +bool GetResizeSizesAndAxes(const GraphViewer& graph_viewer, const Node& node, std::vector& sizes, std::vector& axes, const bool is_nhwc, const gsl::span& input_shape, @@ -117,12 +117,13 @@ bool GetResizeSizesAndAxes(const InitializedTensorSet& initializers, return false; const bool has_axes = !axes.empty(); - const auto& sizes_tensor = *initializers.at(input_defs[3]->Name()); - if (sizes_tensor.dims_size() != 1) { - LOGS(logger, ERROR) << "'sizes' should be a 1D tensor."; + const auto* sizes_init = graph_viewer.GetConstantInitializer(input_defs[3]->Name()); + if (!sizes_init || sizes_init->dims_size() != 1) { + LOGS(logger, ERROR) << "'sizes' should be a 1D constant initializer tensor."; return false; } + const auto& sizes_tensor = *sizes_init; // Number of elements of sizes tensor. const auto num_of_sizes = sizes_tensor.dims()[0]; if (has_axes && num_of_sizes != 2) { @@ -223,17 +224,18 @@ Status ResizeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, // This handles Resize-11 where 'scales' was a required input but 'sizes' were used if provided. bool using_sizes = !sizes_name.empty() && Contains(initializers, sizes_name); if (using_sizes) { - ORT_RETURN_IF_NOT(GetResizeSizesAndAxes(initializers, node, sizes, axes, is_nhwc, input_shape, logger), + ORT_RETURN_IF_NOT(GetResizeSizesAndAxes(model_builder.GetGraphViewer(), node, sizes, axes, is_nhwc, + input_shape, logger), "Error getting Resize sizes"); - webnn_sizes = GetVecUint32FromVecInt64(sizes); + webnn_sizes = GetNarrowedIntfromInt64(sizes); options.set("sizes", emscripten::val::array(webnn_sizes)); } else { - ORT_RETURN_IF_NOT(GetResizeScalesAndAxes(initializers, node, scales, axes, is_nhwc, logger), + ORT_RETURN_IF_NOT(GetResizeScalesAndAxes(model_builder.GetGraphViewer(), node, scales, axes, is_nhwc, logger), "Error getting Resize scales"); options.set("scales", emscripten::val::array(scales)); } - std::vector webnn_axes = GetVecUint32FromVecInt64(axes); + std::vector webnn_axes = GetNarrowedIntfromInt64(axes); options.set("axes", emscripten::val::array(webnn_axes)); emscripten::val input = model_builder.GetOperand(input_defs[0]->Name()); @@ -244,7 +246,7 @@ Status ResizeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, // Operator support related. -bool ResizeOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, +bool ResizeOpBuilder::IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { @@ -305,8 +307,8 @@ bool ResizeOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers // Check for 'sizes' first. // This handles Resize-11 where 'scales' was a required input but 'sizes' were used if provided. // 'scales' or 'sizes' may be empty tensor. - bool using_sizes = !IsEmptyTensor(initializers, sizes_name); - bool using_scales = !using_sizes && !IsEmptyTensor(initializers, scales_name); + bool using_sizes = !IsEmptyTensor(graph_viewer, sizes_name); + bool using_scales = !using_sizes && !IsEmptyTensor(graph_viewer, scales_name); if (!using_scales && !using_sizes) { LOGS(logger, VERBOSE) << "Resize: only one of 'scales' and 'sizes' can be specified"; @@ -326,12 +328,12 @@ bool ResizeOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers const bool is_nhwc = node.Domain() == kMSInternalNHWCDomain; if (using_sizes) { // We are using 'sizes'. std::vector sizes; - if (!GetResizeSizesAndAxes(initializers, node, sizes, axes, is_nhwc, input_shape, logger)) { + if (!GetResizeSizesAndAxes(graph_viewer, node, sizes, axes, is_nhwc, input_shape, logger)) { return false; } } else { // We are using 'scales'. std::vector scales; - if (!GetResizeScalesAndAxes(initializers, node, scales, axes, is_nhwc, logger)) { + if (!GetResizeScalesAndAxes(graph_viewer, node, scales, axes, is_nhwc, logger)) { return false; } } diff --git a/onnxruntime/core/providers/webnn/builders/impl/rotaryEmbedding_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/rotaryEmbedding_op_builder.cc index cbaff79f4fd4f..bdd0c97b7b81c 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/rotaryEmbedding_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/rotaryEmbedding_op_builder.cc @@ -57,9 +57,9 @@ class RotaryEmbeddingOpBuilder : public BaseOpBuilder { // Operator support related. private: - bool IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, + bool IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; - bool HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool HasSupportedInputsImpl(const GraphViewer& graph_viewer, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; bool HasSupportedOutputsImpl(const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; @@ -89,7 +89,7 @@ Status RotaryEmbeddingOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_build emscripten::val wnn_builder = model_builder.GetBuilder(); NodeAttrHelper helper(node); - const bool interleaved = gsl::narrow_cast(helper.Get("interleaved", 0)); + const bool interleaved = static_cast(helper.Get("interleaved", 0)); uint32_t num_heads = helper.Get("num_heads", 0); uint32_t rotary_embedding_dim = helper.Get("rotary_embedding_dim", 0); @@ -159,14 +159,22 @@ Status RotaryEmbeddingOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_build if (position_ids_is_offset) { // We generate a sequence from 0 to sequence_length and add the offset to it. const std::vector position_ids_range_shape = {1, sequence_length}; - emscripten::val position_ids_range_buffer = emscripten::val::global("BigInt64Array").new_(sequence_length); + std::string typed_array_name = "BigInt64Array"; + int position_ids_data_type = ONNX_NAMESPACE::TensorProto_DataType_INT64; + const bool is_int64_supported = model_builder.IsInt64Supported(); + if (!is_int64_supported) { + // Int64 is not supported by current context, use int32 instead. + typed_array_name = "Int32Array"; + position_ids_data_type = ONNX_NAMESPACE::TensorProto_DataType_INT32; + } + emscripten::val position_ids_range_buffer = emscripten::val::global(typed_array_name.c_str()).new_(sequence_length); for (uint32_t i = 0; i < sequence_length; i++) { - position_ids_range_buffer.set(i, emscripten::val::global("BigInt")(i)); + position_ids_range_buffer.set(i, is_int64_supported ? emscripten::val::global("BigInt")(i) : emscripten::val(i)); } emscripten::val position_ids_range_desc = emscripten::val::object(); position_ids_range_desc.set("shape", emscripten::val::array(position_ids_range_shape)); position_ids_range_desc.set("dimensions", emscripten::val::array(position_ids_range_shape)); - position_ids_range_desc.set("dataType", emscripten::val("int64")); + ORT_RETURN_IF_NOT(SetWebnnDataType(position_ids_range_desc, position_ids_data_type), "Unsupported data type"); emscripten::val position_ids_range = wnn_builder.call( "constant", position_ids_range_desc, position_ids_range_buffer); // Add the offset to the sequence. @@ -219,9 +227,17 @@ Status RotaryEmbeddingOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_build sign_buffer.set(0, -1.0f); sign_buffer.set(1, 1.0f); } else if (input_data_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT16) { - sign_buffer = emscripten::val::global("Uint16Array").new_(2); - sign_buffer.set(0, PackFloat32ToUint16AsFloat16(-1.0f)); - sign_buffer.set(1, PackFloat32ToUint16AsFloat16(1.0f)); + if (model_builder.IsFloat16ArrayAvailable()) { + // Float16Array is avaliable - use Float16Array. + sign_buffer = emscripten::val::global("Float16Array").new_(2); + sign_buffer.set(0, -1.0f); + sign_buffer.set(1, 1.0f); + } else { + // Float16Array is not available - use Uint16Array instead. + sign_buffer = emscripten::val::global("Uint16Array").new_(2); + sign_buffer.set(0, PackFloat32ToUint16AsFloat16(-1.0f)); + sign_buffer.set(1, PackFloat32ToUint16AsFloat16(1.0f)); + } } else { return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Unsupported input data type: ", input_data_type); } @@ -259,7 +275,7 @@ Status RotaryEmbeddingOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_build } // Reshape the output to the original shape. The output shape is the same as the input shape. - const std::vector output_shape = GetVecUint32FromVecInt64(input_shape); + const std::vector output_shape = GetNarrowedIntfromInt64(input_shape); emscripten::val reshape_output_options = emscripten::val::object(); reshape_output_options.set("label", node_name + "_reshape_output"); output = wnn_builder.call( @@ -270,7 +286,7 @@ Status RotaryEmbeddingOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_build } // Operator support related. -bool RotaryEmbeddingOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, +bool RotaryEmbeddingOpBuilder::IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { const auto& input_defs = node.InputDefs(); @@ -309,7 +325,7 @@ bool RotaryEmbeddingOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& ini return true; } -bool RotaryEmbeddingOpBuilder::HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, +bool RotaryEmbeddingOpBuilder::HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const { diff --git a/onnxruntime/core/providers/webnn/builders/impl/scatterElements_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/scatterElements_op_builder.cc index 1a68f7862f1ab..f894e8bfbd517 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/scatterElements_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/scatterElements_op_builder.cc @@ -20,9 +20,9 @@ class ScatterElementsOpBuilder : public BaseOpBuilder { const logging::Logger& logger) const override ORT_MUST_USE_RESULT; // Operator support related. - bool IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; - bool HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool HasSupportedInputsImpl(const GraphViewer& graph_viewer, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; }; @@ -53,7 +53,7 @@ Status ScatterElementsOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_build // Operator support related. -bool ScatterElementsOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, const Node& node, +bool ScatterElementsOpBuilder::IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { NodeAttrHelper helper(node); @@ -65,7 +65,7 @@ bool ScatterElementsOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* return true; } -bool ScatterElementsOpBuilder::HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, +bool ScatterElementsOpBuilder::HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const { const auto& data = *node.InputDefs()[0]; diff --git a/onnxruntime/core/providers/webnn/builders/impl/scatterND_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/scatterND_op_builder.cc index 2b123dc2e9323..e61ac3dcc9617 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/scatterND_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/scatterND_op_builder.cc @@ -20,9 +20,9 @@ class ScatterNDOpBuilder : public BaseOpBuilder { const logging::Logger& logger) const override ORT_MUST_USE_RESULT; // Operator support related. - bool IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; - bool HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool HasSupportedInputsImpl(const GraphViewer& graph_viewer, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; }; @@ -45,7 +45,7 @@ Status ScatterNDOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, co // Operator support related. -bool ScatterNDOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, const Node& node, +bool ScatterNDOpBuilder::IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { NodeAttrHelper helper(node); @@ -57,7 +57,7 @@ bool ScatterNDOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* initia return true; } -bool ScatterNDOpBuilder::HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, +bool ScatterNDOpBuilder::HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const { const auto& data = *node.InputDefs()[0]; diff --git a/onnxruntime/core/providers/webnn/builders/impl/shape_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/shape_op_builder.cc index 360c6588898f1..2bea1af896eee 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/shape_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/shape_op_builder.cc @@ -29,12 +29,20 @@ Status ShapeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const auto rank = static_cast(input_shape.size()); emscripten::val desc = emscripten::val::object(); - ORT_RETURN_IF_NOT(SetWebnnDataType(desc, ONNX_NAMESPACE::TensorProto_DataType_INT64), "Unsupported data type"); emscripten::val dims = emscripten::val::array(); dims.call("push", rank); desc.set("dimensions", dims); desc.set("shape", dims); - emscripten::val shape_buffer = emscripten::val::global("BigInt64Array").new_(emscripten::val::array(input_shape)); + int data_type = ONNX_NAMESPACE::TensorProto_DataType_INT64; + std::string typed_array_name = "BigInt64Array"; + if (!model_builder.IsInt64Supported()) { + // Int64 is not supported by current context, use int32 instead. + data_type = ONNX_NAMESPACE::TensorProto_DataType_INT32; + typed_array_name = "Int32Array"; + } + ORT_RETURN_IF_NOT(SetWebnnDataType(desc, data_type), "Unsupported data type"); + emscripten::val shape_buffer = + emscripten::val::global(typed_array_name.c_str()).new_(emscripten::val::array(input_shape)); emscripten::val shape_constant = model_builder.GetBuilder().call("constant", desc, shape_buffer); NodeAttrHelper helper(node); diff --git a/onnxruntime/core/providers/webnn/builders/impl/slice_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/slice_op_builder.cc index 8baa450204aff..6206ac23e4bd4 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/slice_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/slice_op_builder.cc @@ -2,7 +2,6 @@ // Copyright (c) Intel Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/common/safeint.h" #include "core/framework/tensorprotoutils.h" #include "core/optimizer/initializer.h" #include "core/providers/common.h" @@ -25,9 +24,9 @@ class SliceOpBuilder : public BaseOpBuilder { private: Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, const logging::Logger& logger) const override ORT_MUST_USE_RESULT; - bool IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, + bool IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; - bool HasSupportedInputsImpl(const InitializedTensorSet& initializers, const Node& node, + bool HasSupportedInputsImpl(const GraphViewer& graph_viewer, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; // TODO: Support Slice opset < 10, which uses attributes for starts and ends. int GetMinSupportedOpSet(const Node& /* node */) const override { return 10; } @@ -116,8 +115,8 @@ Status SliceOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const emscripten::val output = reverse_output; if (is_slice_required) { - std::vector starts = GetVecUint32FromVecInt64(compute_metadata.starts_); - std::vector steps = GetVecUint32FromVecInt64(compute_metadata.steps_); + std::vector starts = GetNarrowedIntfromInt64(compute_metadata.starts_); + std::vector steps = GetNarrowedIntfromInt64(compute_metadata.steps_); std::vector sizes(rank); std::transform(compute_metadata.ends_.cbegin(), compute_metadata.ends_.cend(), compute_metadata.starts_.cbegin(), sizes.begin(), [](int64_t i, int64_t j) { return SafeInt(i - j); }); @@ -133,7 +132,7 @@ Status SliceOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const return Status::OK(); } -bool SliceOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, +bool SliceOpBuilder::IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { const auto& name = node.Name(); const auto& op_type = node.OpType(); @@ -153,7 +152,8 @@ bool SliceOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, for (size_t i = 1; i < input_defs.size(); i++) { // Optional tensors (axes, steps) can be indicated by an empty name, just ignore it. const std::string input_name = GetTensorName(input_defs, i); - if (!input_name.empty() && !Contains(initializers, input_name)) { + const auto* init = graph_viewer.GetConstantInitializer(input_name); + if (!input_name.empty() && !init) { LOGS(logger, VERBOSE) << "Input [" << input_name << "] of " << op_type << " [" << name << "] must be known as initializer"; return false; @@ -163,7 +163,7 @@ bool SliceOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, return true; } -bool SliceOpBuilder::HasSupportedInputsImpl(const InitializedTensorSet& initializers, const Node& node, +bool SliceOpBuilder::HasSupportedInputsImpl(const GraphViewer& graph_viewer, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const { const auto& input_defs = node.InputDefs(); const auto& input = *input_defs[0]; @@ -175,7 +175,8 @@ bool SliceOpBuilder::HasSupportedInputsImpl(const InitializedTensorSet& initiali // If there is step < 0, check data type support of reverse. if (TensorExists(input_defs, 4)) { std::vector steps; - if (!ReadIntArrayFrom1DTensor(*initializers.at(input_defs[4]->Name()), steps, logger)) + const auto* init = graph_viewer.GetConstantInitializer(input_defs[4]->Name()); + if (!init || !ReadIntArrayFrom1DTensor(*init, steps, logger)) return false; if (std::any_of(steps.begin(), steps.end(), [](int64_t step) { return step < 0; })) { if (!IsDataTypeSupportedByWebNNOp(op_type, "reverse", input_type, wnn_limits, "input", "data", logger)) { diff --git a/onnxruntime/core/providers/webnn/builders/impl/softmax_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/softmax_op_builder.cc index b1b737b114998..23e73bb8f1e74 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/softmax_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/softmax_op_builder.cc @@ -2,7 +2,6 @@ // Copyright (c) Intel Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/common/safeint.h" #include "core/providers/common.h" #include "core/providers/shared/utils/utils.h" #include "core/providers/webnn/builders/helper.h" @@ -22,7 +21,7 @@ class SoftmaxOpBuilder : public BaseOpBuilder { // Operator support related. private: - bool IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; }; @@ -49,7 +48,7 @@ Status SoftmaxOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, // Operator support related. -bool SoftmaxOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, +bool SoftmaxOpBuilder::IsOpSupportedImpl(const GraphViewer&, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { diff --git a/onnxruntime/core/providers/webnn/builders/impl/split_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/split_op_builder.cc index 06dbacf995a28..8094d3024a321 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/split_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/split_op_builder.cc @@ -2,7 +2,6 @@ // Copyright (c) Intel Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/common/safeint.h" #include "core/optimizer/initializer.h" #include "core/providers/common.h" #include "core/providers/shared/utils/utils.h" @@ -26,7 +25,7 @@ class SplitOpBuilder : public BaseOpBuilder { // Operator support related. private: - bool IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, + bool IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; bool HasSupportedOutputsImpl(const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; @@ -75,8 +74,8 @@ Status SplitOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, // Check that the splits evenly divide. if (split_count > 0 && splits.empty() && input_shape[axis] % split_count != 0) { // Divide inputs into variable size outputs: - splits.insert(splits.end(), split_count - 1, narrow(input_shape[axis]) / split_count); - splits.insert(splits.end(), narrow(input_shape[axis]) % split_count); + splits.insert(splits.end(), split_count - 1, SafeInt(input_shape[axis]) / split_count); + splits.insert(splits.end(), SafeInt(input_shape[axis]) % split_count); } if (splits.empty()) { @@ -95,7 +94,7 @@ Status SplitOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, // Operator support related. -bool SplitOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, +bool SplitOpBuilder::IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { @@ -115,12 +114,13 @@ bool SplitOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, const std::string split_name = GetTensorName(input_defs, 1); // Inputs contain optional 'split' input. if (!split_name.empty()) { - if (!Contains(initializers, split_name)) { + const auto* split_init = graph_viewer.GetConstantInitializer(split_name); + if (!split_init) { LOGS(logger, VERBOSE) << "The split must be a constant initializer."; return false; } // Values should be >= 0. Sum of the values must be equal to the dim value at 'axis' specified. - const auto& split_tensor = *initializers.at(input_defs[1]->Name()); + const auto& split_tensor = *split_init; if (split_tensor.data_type() != ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64) { LOGS(logger, VERBOSE) << "The type of tensor's element data must be INT64."; return false; diff --git a/onnxruntime/core/providers/webnn/builders/impl/squeeze_unsqueeze_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/squeeze_unsqueeze_op_builder.cc index 5eff96873b8c4..1ba6df9febf14 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/squeeze_unsqueeze_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/squeeze_unsqueeze_op_builder.cc @@ -2,7 +2,6 @@ // Copyright (c) Intel Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/common/safeint.h" #include "core/providers/common.h" #include "core/providers/shared/utils/utils.h" #include "core/providers/webnn/builders/helper.h" @@ -28,7 +27,7 @@ class SqueezeUnsqueezeOpBuilder : public BaseOpBuilder { // Operator support related. private: - bool IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, + bool IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; }; @@ -86,7 +85,7 @@ Status SqueezeUnsqueezeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_buil emscripten::val output = emscripten::val::undefined(); // Use WebNN's reshape to implement Squeeze/Unsqueeze. - std::vector new_shape = GetVecUint32FromVecInt64(input_shape); + std::vector new_shape = GetNarrowedIntfromInt64(input_shape); // Sort axes_data in ascending order. std::sort(axes_data.begin(), axes_data.end()); if (op_type == "Squeeze") { @@ -122,7 +121,7 @@ Status SqueezeUnsqueezeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_buil // Operator support related. -bool SqueezeUnsqueezeOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, +bool SqueezeUnsqueezeOpBuilder::IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { @@ -141,7 +140,8 @@ bool SqueezeUnsqueezeOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& in if (node.SinceVersion() >= 13) { const std::string axes_name = GetTensorName(input_defs, 1); if (!axes_name.empty()) { - if (!Contains(initializers, axes_name)) { + const auto* init = graph_viewer.GetConstantInitializer(axes_name); + if (!init) { LOGS(logger, ERROR) << "Input axes of " << op_type << " is not present and constant"; return false; } diff --git a/onnxruntime/core/providers/webnn/builders/impl/ternary_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/ternary_op_builder.cc index a233ba82ebbc6..f6c1744ca7a3e 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/ternary_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/ternary_op_builder.cc @@ -18,7 +18,7 @@ class TernaryOpBuilder : public BaseOpBuilder { private: Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, const logging::Logger& logger) const override ORT_MUST_USE_RESULT; - bool HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, + bool HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const override; }; @@ -46,7 +46,7 @@ Status TernaryOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, cons return Status::OK(); } -bool TernaryOpBuilder::HasSupportedInputsImpl(const InitializedTensorSet& /* initializers */, const Node& node, +bool TernaryOpBuilder::HasSupportedInputsImpl(const GraphViewer&, const Node& node, const emscripten::val& wnn_limits, const logging::Logger& logger) const { const auto& input_defs = node.InputDefs(); const std::string_view op_type = node.OpType(); diff --git a/onnxruntime/core/providers/webnn/builders/impl/tile_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/tile_op_builder.cc index 672a3a510d54d..29b232026d7df 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/tile_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/tile_op_builder.cc @@ -2,7 +2,6 @@ // Copyright (c) Intel Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/common/safeint.h" #include "core/framework/tensorprotoutils.h" #include "core/optimizer/initializer.h" #include "core/providers/common.h" @@ -27,7 +26,7 @@ class TileOpBuilder : public BaseOpBuilder { // Operator support related. private: - bool IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, + bool IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; }; @@ -66,13 +65,14 @@ Status TileOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, // Operator support related. -bool TileOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, +bool TileOpBuilder::IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { const auto& input_defs = node.InputDefs(); const auto& repetitions_name = input_defs[1]->Name(); - if (!Contains(initializers, repetitions_name)) { + const auto* init = graph_viewer.GetConstantInitializer(repetitions_name); + if (!init) { LOGS(logger, VERBOSE) << "Repetitions of tile must be a constant initializer"; return false; } diff --git a/onnxruntime/core/providers/webnn/builders/impl/transpose_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/transpose_op_builder.cc index 3a5e39f7f7a56..452071f469c4f 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/transpose_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/transpose_op_builder.cc @@ -2,7 +2,6 @@ // Copyright (c) Intel Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/common/safeint.h" #include "core/providers/shared/utils/utils.h" #include "core/providers/webnn/builders/helper.h" #include "core/providers/webnn/builders/model_builder.h" @@ -41,7 +40,7 @@ Status TransposeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, emscripten::val input = model_builder.GetOperand(input_defs[0]->Name()); emscripten::val options = emscripten::val::object(); options.set("label", node.Name()); - std::vector permutation = GetVecUint32FromVecInt64(perm); + std::vector permutation = GetNarrowedIntfromInt64(perm); options.set("permutation", emscripten::val::array(permutation)); emscripten::val output = model_builder.GetBuilder().call("transpose", input, options); model_builder.AddOperand(node.OutputDefs()[0]->Name(), std::move(output)); diff --git a/onnxruntime/core/providers/webnn/builders/impl/triangular_op_builder.cc b/onnxruntime/core/providers/webnn/builders/impl/triangular_op_builder.cc index 0c818533918a4..ca98d8264fdcd 100644 --- a/onnxruntime/core/providers/webnn/builders/impl/triangular_op_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/impl/triangular_op_builder.cc @@ -24,7 +24,7 @@ class TriangularOpBuilder : public BaseOpBuilder { // Operator support related. private: - bool IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node, + bool IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const override; }; @@ -59,7 +59,7 @@ Status TriangularOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, std::vector unpacked_tensor; ORT_RETURN_IF_ERROR(onnxruntime::utils::UnpackInitializerData(diagonal_tensor, unpacked_tensor)); const auto diagonal = *reinterpret_cast(unpacked_tensor.data()); - options.set("diagonal", narrow(diagonal)); + options.set("diagonal", SafeInt(diagonal).Ref()); } output = model_builder.GetBuilder().call("triangular", input, options); @@ -69,7 +69,7 @@ Status TriangularOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, } // Operator support related. -bool TriangularOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initializers, +bool TriangularOpBuilder::IsOpSupportedImpl(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType /* device_type */, const logging::Logger& logger) const { @@ -87,7 +87,8 @@ bool TriangularOpBuilder::IsOpSupportedImpl(const InitializedTensorSet& initiali const std::string diagonal_name = GetTensorName(input_defs, 1); // Inputs contain optional 'diagonal' input. if (!diagonal_name.empty()) { - if (!Contains(initializers, diagonal_name)) { + const auto* init = graph_viewer.GetConstantInitializer(diagonal_name); + if (!init) { LOGS(logger, VERBOSE) << "The diagonal must be a constant initializer."; return false; } diff --git a/onnxruntime/core/providers/webnn/builders/model.cc b/onnxruntime/core/providers/webnn/builders/model.cc index 35964d85862e4..40fdfc609e6a1 100644 --- a/onnxruntime/core/providers/webnn/builders/model.cc +++ b/onnxruntime/core/providers/webnn/builders/model.cc @@ -8,7 +8,6 @@ #include "core/common/common.h" #include "core/common/inlined_containers.h" #include "core/common/logging/logging.h" -#include "core/common/safeint.h" #include "core/graph/onnx_protobuf.h" #include "core/providers/common.h" #include "model.h" @@ -157,7 +156,7 @@ onnxruntime::common::Status Model::Compute(const InlinedHashMap& inputs, const InlinedHashMap& outputs) { - auto jsepEnsureTensor = emscripten::val::module_property("jsepEnsureTensor"); + auto webnnEnsureTensor = emscripten::val::module_property("webnnEnsureTensor"); auto promises = emscripten::val::array(); for (const auto& [_, tensor] : inputs) { emscripten::val shape = emscripten::val::array(); @@ -165,7 +164,7 @@ onnxruntime::common::Status Model::Dispatch(const InlinedHashMap(dim); shape.call("push", dim_val); } - auto ml_tensor = jsepEnsureTensor(emscripten::val::undefined(), reinterpret_cast(tensor.buffer), tensor.tensor_info.data_type, shape, true); + auto ml_tensor = webnnEnsureTensor(emscripten::val::undefined(), reinterpret_cast(tensor.buffer), tensor.tensor_info.data_type, shape, true); promises.call("push", ml_tensor); } for (const auto& [_, tensor] : outputs) { @@ -174,7 +173,7 @@ onnxruntime::common::Status Model::Dispatch(const InlinedHashMap(dim); shape.call("push", dim_val); } - auto ml_tensor = jsepEnsureTensor(emscripten::val::undefined(), reinterpret_cast(tensor.buffer), tensor.tensor_info.data_type, shape, false); + auto ml_tensor = webnnEnsureTensor(emscripten::val::undefined(), reinterpret_cast(tensor.buffer), tensor.tensor_info.data_type, shape, false); promises.call("push", ml_tensor); } auto ml_tensors = emscripten::val::global("Promise").call("all", promises).await(); diff --git a/onnxruntime/core/providers/webnn/builders/model_builder.cc b/onnxruntime/core/providers/webnn/builders/model_builder.cc index ace6519a1fc11..399cc5faf6273 100644 --- a/onnxruntime/core/providers/webnn/builders/model_builder.cc +++ b/onnxruntime/core/providers/webnn/builders/model_builder.cc @@ -9,7 +9,6 @@ #include "helper.h" #include "op_builder_factory.h" -#include "core/common/safeint.h" #include "core/framework/tensorprotoutils.h" #include "core/providers/common.h" #include "core/providers/shared/utils/utils.h" @@ -34,6 +33,9 @@ ModelBuilder::ModelBuilder(const GraphViewer& graph_viewer, const logging::Logge if (!wnn_builder_.as()) { ORT_THROW("Failed to create WebNN builder."); } + if (wnn_limits["input"]["dataTypes"].call("includes", emscripten::val("int64")).as()) { + is_int64_supported_ = true; + } } Status ModelBuilder::Initialize() { @@ -125,6 +127,10 @@ Status ModelBuilder::RegisterInitializers() { emscripten::val view = emscripten::val::undefined(); std::byte* tensor_ptr = nullptr; + // A flag to indicate if we should convert int64 to int32. + const bool should_convert_int64_to_int32 = !is_int64_supported_ && + data_type == ONNX_NAMESPACE::TensorProto_DataType_INT64; + if (utils::HasExternalData(tensor)) { // Create WebNN Constant from external data. std::basic_string external_file_path; @@ -133,12 +139,13 @@ Status ModelBuilder::RegisterInitializers() { ORT_RETURN_IF_ERROR(utils::GetExternalDataInfo( tensor, graph_viewer_.ModelPath(), external_file_path, data_offset, tensor_byte_size)); - auto jsepRegisterMLConstant = emscripten::val::module_property("jsepRegisterMLConstant"); - operand = jsepRegisterMLConstant(emscripten::val(external_file_path), - static_cast(data_offset), - static_cast(tensor_byte_size), - wnn_builder_, - desc); + auto webnnRegisterMLConstant = emscripten::val::module_property("webnnRegisterMLConstant"); + operand = webnnRegisterMLConstant(emscripten::val(external_file_path), + static_cast(data_offset), + static_cast(tensor_byte_size), + wnn_builder_, + desc, + should_convert_int64_to_int32); } else { if (tensor.has_raw_data()) { tensor_ptr = reinterpret_cast(const_cast(tensor.raw_data().c_str())); @@ -195,15 +202,31 @@ Status ModelBuilder::RegisterInitializers() { break; } + // If int64 is not supported, convert int64 to int32. + std::vector int32_data; + if (should_convert_int64_to_int32) { + try { + int32_data = GetNarrowedIntfromInt64( + gsl::span(reinterpret_cast(tensor_ptr), num_elements)); + LOGS(logger_, VERBOSE) << "Initializer '" << name << "' is converted from int64 to int32."; + } catch (const std::exception& e) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, e.what()); + } + view = emscripten::val{emscripten::typed_memory_view(num_elements, int32_data.data())}; + + desc.set("dataType", emscripten::val("int32")); + } + // Wasm memory grow will cause all array buffers reallocation, which will be treated as detached // buffers in JS side. Simply create a copy to fix it. - operand = wnn_builder_.call("constant", desc, view.call("slice")); + view = view.call("slice"); + operand = wnn_builder_.call("constant", desc, view["buffer"]); } } else { // TODO: support other type. return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "The initializer of graph has unsupported type, name: ", - tensor.name(), " type: ", data_type); + name, " type: ", data_type); } wnn_operands_.insert(std::make_pair(name, operand)); } @@ -259,8 +282,12 @@ Status ModelBuilder::RegisterModelInputOutput(const NodeArg& node_arg, bool is_i } if (is_input) { + if (data_type == ONNX_NAMESPACE::TensorProto_DataType_INT64 && !is_int64_supported_) { + // Int64 is not supported by current context, use int32 instead. + desc.set("dataType", emscripten::val("int32")); + } wnn_operands_.insert(std::make_pair(name, wnn_builder_.call("input", name, desc))); - emscripten::val::module_property("jsepRegisterGraphInput")(name); + emscripten::val::module_property("webnnRegisterGraphInput")(name); input_names_.push_back(name); } else { output_names_.push_back(name); @@ -350,7 +377,8 @@ Status ModelBuilder::AddOperandFromPersistMemoryBuffer( emscripten::val operand = emscripten::val::object(); // Wasm memory grow will cause all array buffers reallocation, which will be treated as detached // buffers in JS side. Simply create a copy to fix it. - operand = wnn_builder_.call("constant", desc, view.call("slice")); + view = view.call("slice"); + operand = wnn_builder_.call("constant", desc, view["buffer"]); AddOperand(name, operand); mem_persist_buffers_.push_back(std::move(persist_buffer)); diff --git a/onnxruntime/core/providers/webnn/builders/model_builder.h b/onnxruntime/core/providers/webnn/builders/model_builder.h index 4e2d84f481df0..f45e38935651f 100644 --- a/onnxruntime/core/providers/webnn/builders/model_builder.h +++ b/onnxruntime/core/providers/webnn/builders/model_builder.h @@ -30,9 +30,12 @@ class ModelBuilder { Status Compile(std::unique_ptr& model) ORT_MUST_USE_RESULT; // Accessors for members. + bool IsFloat16ArrayAvailable() const { return is_float16array_available_; } const GraphViewer& GetGraphViewer() const { return graph_viewer_; } InitializedTensorSet GetInitializerTensors(); + bool IsInt64Supported() const { return is_int64_supported_; } + const emscripten::val& GetBuilder() const { return wnn_builder_; } const emscripten::val& GetContext() const { return wnn_context_; } const emscripten::val& GetOperand(const std::string& name) const { return wnn_operands_.at(name); } @@ -68,9 +71,12 @@ class ModelBuilder { private: const GraphViewer& graph_viewer_; const logging::Logger& logger_; + const bool is_float16array_available_ = !emscripten::val::global("Float16Array").isUndefined() && + emscripten::val::global("Float16Array").hasOwnProperty("from"); emscripten::val wnn_context_ = emscripten::val::undefined(); emscripten::val wnn_builder_ = emscripten::val::undefined(); + bool is_int64_supported_ = false; DataLayout preferred_layout_; WebnnDeviceType wnn_device_type_; emscripten::val wnn_limits_ = emscripten::val::undefined(); @@ -172,9 +178,12 @@ const emscripten::val& ModelBuilder::CreateOrGetConstant(const int32_t& data_typ } break; case ONNX_NAMESPACE::TensorProto_DataType_FLOAT16: - buffer = emscripten::val::global("Uint16Array").new_(num_elements); + buffer = is_float16array_available_ + ? emscripten::val::global("Float16Array").new_(num_elements) + : emscripten::val::global("Uint16Array").new_(num_elements); if (value) { - buffer.call("fill", emscripten::val(PackFloat32ToUint16AsFloat16(value))); + buffer.call("fill", + emscripten::val(is_float16array_available_ ? value : PackFloat32ToUint16AsFloat16(value))); } break; case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: diff --git a/onnxruntime/core/providers/webnn/builders/op_builder.h b/onnxruntime/core/providers/webnn/builders/op_builder.h index bb69a6a545597..636b1dc9f478a 100644 --- a/onnxruntime/core/providers/webnn/builders/op_builder.h +++ b/onnxruntime/core/providers/webnn/builders/op_builder.h @@ -28,7 +28,7 @@ class IOpBuilder { // Operator support related. public: // Check if an operator is supported. - virtual bool IsOpSupported(const InitializedTensorSet& initializers, const Node& node, + virtual bool IsOpSupported(const GraphViewer& graph_viewer, const Node& node, const WebnnDeviceType device_type, const emscripten::val& wnn_limits, const logging::Logger& logger) const = 0; }; diff --git a/onnxruntime/core/providers/webnn/data_transfer.cc b/onnxruntime/core/providers/webnn/data_transfer.cc index 44e9bf9edf3d9..aa85277b72453 100644 --- a/onnxruntime/core/providers/webnn/data_transfer.cc +++ b/onnxruntime/core/providers/webnn/data_transfer.cc @@ -29,11 +29,11 @@ common::Status DataTransfer::CopyTensor(const Tensor& src, Tensor& dst) const { const auto& dst_device = dst.Location().device; if (dst_device.Type() == OrtDevice::GPU) { - EM_ASM({ Module.jsepUploadTensor($0, HEAPU8.subarray($1, $1 + $2)); }, dst_data, reinterpret_cast(src_data), bytes); + EM_ASM({ Module.webnnUploadTensor($0, HEAPU8.subarray($1, $1 + $2)); }, dst_data, reinterpret_cast(src_data), bytes); } else { - auto jsepDownloadTensor = emscripten::val::module_property("jsepDownloadTensor"); + auto webnnDownloadTensor = emscripten::val::module_property("webnnDownloadTensor"); auto subarray = emscripten::typed_memory_view(bytes, static_cast(dst_data)); - jsepDownloadTensor(reinterpret_cast(src_data), subarray).await(); + webnnDownloadTensor(reinterpret_cast(src_data), subarray).await(); } } diff --git a/onnxruntime/core/providers/webnn/webnn_execution_provider.cc b/onnxruntime/core/providers/webnn/webnn_execution_provider.cc index df95b653bd863..2da7c6499933a 100644 --- a/onnxruntime/core/providers/webnn/webnn_execution_provider.cc +++ b/onnxruntime/core/providers/webnn/webnn_execution_provider.cc @@ -10,7 +10,6 @@ #include "core/framework/kernel_registry.h" #include "core/graph/graph_viewer.h" #include "core/session/onnxruntime_cxx_api.h" -#include "core/common/safeint.h" #include "core/providers/webnn/allocator.h" #include "core/providers/webnn/data_transfer.h" #include "core/providers/partitioning_utils.h" @@ -56,6 +55,7 @@ WebNNExecutionProvider::~WebNNExecutionProvider() {} std::vector> WebNNExecutionProvider::GetCapability(const onnxruntime::GraphViewer& graph_viewer, const IKernelLookup& /*kernel_registries*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const { // For subgraph which is the attribute of the control flow nodes, part of its initializers are stored in its // ancestor graphs as common initializers shared for other subgraphs. We need to collect all of them used for @@ -283,7 +283,7 @@ class WebNNMemcpy : public OpKernel { explicit WebNNMemcpy(const OpKernelInfo& info) : OpKernel(info) {} Status Compute(OpKernelContext* context) const override { - auto jsepEnsureTensor = emscripten::val::module_property("jsepEnsureTensor"); + auto webnnEnsureTensor = emscripten::val::module_property("webnnEnsureTensor"); const auto* X = context->Input(0); ORT_ENFORCE(X != nullptr, "Memcpy: input tensor is null"); auto* Y = context->Output(0, X->Shape()); @@ -293,9 +293,10 @@ class WebNNMemcpy : public OpKernel { shape.call("push", SafeInt(dim).Ref()); } - jsepEnsureTensor(reinterpret_cast(Y->MutableDataRaw()), - Y->GetElementType(), - shape, false) + webnnEnsureTensor(emscripten::val::undefined(), + reinterpret_cast(Y->MutableDataRaw()), + Y->GetElementType(), + shape, false) .await(); const auto* data_transfer = Info().GetDataTransferManager().GetDataTransfer(X->Location().device, Y->Location().device); diff --git a/onnxruntime/core/providers/webnn/webnn_execution_provider.h b/onnxruntime/core/providers/webnn/webnn_execution_provider.h index e806dc340d53e..b8775e717668a 100644 --- a/onnxruntime/core/providers/webnn/webnn_execution_provider.h +++ b/onnxruntime/core/providers/webnn/webnn_execution_provider.h @@ -25,6 +25,7 @@ class WebNNExecutionProvider : public IExecutionProvider { std::vector> GetCapability(const onnxruntime::GraphViewer& graph_viewer, const IKernelLookup& /*kernel_registries*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const override; DataLayout GetPreferredLayout() const override { return preferred_layout_; } diff --git a/onnxruntime/core/providers/xnnpack/nn/max_pool.cc b/onnxruntime/core/providers/xnnpack/nn/max_pool.cc index c828ae9400174..8d972f7d63bc1 100644 --- a/onnxruntime/core/providers/xnnpack/nn/max_pool.cc +++ b/onnxruntime/core/providers/xnnpack/nn/max_pool.cc @@ -57,7 +57,7 @@ bool MaxPool::IsOnnxNodeSupported(const NodeUnit& node_unit, // input of maxpool could be fp16/fp32/fp64,i8/u8 according to ONNX if (x_type == nullptr || (x_type->tensor_type().elem_type() != ONNX_NAMESPACE::TensorProto_DataType_FLOAT && -// because pool_fp16_op_test can be enabled by other preprocessor, for example, COREML_ENABLE_MLPROGRAM +// because pool_fp16_op_test can be enabled by other preprocessor, for example, USE_COREML #ifdef XNNPACK_FP16_SUPPORTED x_type->tensor_type().elem_type() != ONNX_NAMESPACE::TensorProto_DataType_FLOAT16 && #endif diff --git a/onnxruntime/core/providers/xnnpack/xnnpack_execution_provider.cc b/onnxruntime/core/providers/xnnpack/xnnpack_execution_provider.cc index 641f8b0729d0a..ab14c083884d3 100644 --- a/onnxruntime/core/providers/xnnpack/xnnpack_execution_provider.cc +++ b/onnxruntime/core/providers/xnnpack/xnnpack_execution_provider.cc @@ -258,6 +258,7 @@ static void AddComputeCapabilityForEachNodeInNodeUnit( std::vector> XnnpackExecutionProvider::GetCapability( const onnxruntime::GraphViewer& graph, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const { const auto& logger = *GetLogger(); std::vector> capabilities; diff --git a/onnxruntime/core/providers/xnnpack/xnnpack_execution_provider.h b/onnxruntime/core/providers/xnnpack/xnnpack_execution_provider.h index 152bef1a1c52c..9c4d2484f9f4b 100644 --- a/onnxruntime/core/providers/xnnpack/xnnpack_execution_provider.h +++ b/onnxruntime/core/providers/xnnpack/xnnpack_execution_provider.h @@ -33,6 +33,7 @@ class XnnpackExecutionProvider : public IExecutionProvider { std::vector> GetCapability( const onnxruntime::GraphViewer& graph_viewer, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const override; std::shared_ptr GetKernelRegistry() const override; diff --git a/onnxruntime/core/session/abi_session_options.cc b/onnxruntime/core/session/abi_session_options.cc index 7ef23d6c9e895..e50ee5738c30e 100644 --- a/onnxruntime/core/session/abi_session_options.cc +++ b/onnxruntime/core/session/abi_session_options.cc @@ -1,17 +1,18 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/graph/onnx_protobuf.h" -#include "core/common/inlined_containers.h" -#include "core/session/onnxruntime_c_api.h" -#include "core/session/ort_apis.h" -#include "core/framework/error_code_helper.h" -#include #include +#include #include + +#include "core/common/inlined_containers.h" +#include "core/framework/error_code_helper.h" +#include "core/graph/onnx_protobuf.h" +#include "core/session/abi_session_options_impl.h" #include "core/session/inference_session.h" -#include "abi_session_options_impl.h" -#include "api_utils.h" +#include "core/session/onnxruntime_c_api.h" +#include "core/session/ort_apis.h" +#include "core/session/utils.h" OrtSessionOptions::~OrtSessionOptions() = default; @@ -339,3 +340,11 @@ ORT_API_STATUS_IMPL(OrtApis::SetDeterministicCompute, _Inout_ OrtSessionOptions* return nullptr; API_IMPL_END } + +ORT_API_STATUS_IMPL(OrtApis::SessionOptionsSetLoadCancellationFlag, _Inout_ OrtSessionOptions* options, + _In_ bool is_cancel) { + API_IMPL_BEGIN + options->value.SetLoadCancellationFlag(is_cancel); + return nullptr; + API_IMPL_END +} diff --git a/onnxruntime/core/session/api_utils.cc b/onnxruntime/core/session/api_utils.cc deleted file mode 100644 index f7cb8520b1e5d..0000000000000 --- a/onnxruntime/core/session/api_utils.cc +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "api_utils.h" - -onnxruntime::common::Status CopyStringToOutputArg(std::string_view str, const char* err_msg, char* out, size_t* size) { - const size_t str_len = str.size(); - const size_t req_size = str_len + 1; - - if (out == nullptr) { // User is querying the total output buffer size - *size = req_size; - return onnxruntime::common::Status::OK(); - } - - if (*size >= req_size) { // User provided a buffer of sufficient size - std::memcpy(out, str.data(), str_len); - out[str_len] = '\0'; - *size = req_size; - return onnxruntime::common::Status::OK(); - } - - // User has provided a buffer that is not large enough - *size = req_size; - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, err_msg); -} diff --git a/onnxruntime/core/session/api_utils.h b/onnxruntime/core/session/api_utils.h deleted file mode 100644 index 27c2bbd66f8d5..0000000000000 --- a/onnxruntime/core/session/api_utils.h +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "core/common/common.h" -#include - -onnxruntime::common::Status CopyStringToOutputArg(std::string_view str, const char* err_msg, char* out, size_t* size); diff --git a/onnxruntime/core/session/custom_ops.cc b/onnxruntime/core/session/custom_ops.cc index 8492391172133..f583767346d88 100644 --- a/onnxruntime/core/session/custom_ops.cc +++ b/onnxruntime/core/session/custom_ops.cc @@ -20,7 +20,7 @@ #include "core/framework/tensorprotoutils.h" #include "core/graph/onnx_protobuf.h" #include "core/session/allocator_adapters.h" -#include "core/session/api_utils.h" +#include "core/session/utils.h" #include "core/session/custom_ops.h" #include "core/session/inference_session.h" #include "core/session/ort_apis.h" @@ -900,13 +900,14 @@ KernelCreateInfo CreateKernelCreateInfo(const std::string& domain, const OrtCust ONNX_NAMESPACE::OpSchema CreateSchema(const std::string& domain, const std::vector& ops) { // The function registers the first schema assuming all the other one are the same except the types constraints. ORT_ENFORCE(ops.size() > 0, "No kernels to registers."); - int undefined = 0; + int num_inputs_with_dynamic_type = 0; // Creation of the schema for the first kernel in ops. const OrtCustomOp* op = *ops.begin(); ONNX_NAMESPACE::OpSchema schema(op->GetName(op), "custom op registered at runtime", 0); - auto create_type_constraint = [&ops, &schema, &undefined](const OrtCustomOp* op, int count, int i, bool is_input) { + auto create_type_constraint = [&ops, &schema, &num_inputs_with_dynamic_type]( + const OrtCustomOp* op, int count, int i, bool is_input) { onnx::OpSchema::FormalParameterOption option = onnx::OpSchema::FormalParameterOption::Single; bool is_homogeneous = true; int min_arity = 1; @@ -976,7 +977,9 @@ ONNX_NAMESPACE::OpSchema CreateSchema(const std::string& domain, const std::vect } else { // all_types is empty. As mentioned in the previous loop, all types are allowed. schema.TypeConstraint(name, DataTypeImpl::ToString(SUPPORTED_TENSOR_TYPES), "all types"); - undefined++; + if (is_input) { + ++num_inputs_with_dynamic_type; + } } }; @@ -985,19 +988,21 @@ ONNX_NAMESPACE::OpSchema CreateSchema(const std::string& domain, const std::vect create_type_constraint(op, static_cast(input_count), static_cast(i), true); } + const bool have_shape_infer_fn = op->version >= min_ort_version_with_shape_inference && op->InferOutputShapeFn; + const size_t output_count = op->GetOutputTypeCount(op); for (size_t i = 0; i < output_count; i++) { const auto type = op->GetOutputType(op, i); if (ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED == type) { if (op->GetOutputCharacteristic(op, i) == OrtCustomOpInputOutputCharacteristic::INPUT_OUTPUT_REQUIRED) { - ORT_ENFORCE(1 == undefined, - "There must be one (and only one) dynamic typed input to the custom op. " - "Its type info at runtime will be used to infer the type info of this dynamic typed output " - "which is required for the success of the model loading step. " - "More than one dynamic typed inputs are currently not supported as differing types at runtime " - "means the output type cannot be inferred without which model loading cannot proceed."); + // if there's a dynamically typed input and output we infer they both have the same type from the input. + // if that isn't the case the user must provide an output shape inference fn which must set the output type. + ORT_ENFORCE(num_inputs_with_dynamic_type == 1 || have_shape_infer_fn, + "The type of a dynamically typed output can be inferred from a single dynamically typed input, " + "or by a user provided OrtCustomOp->InferOutputShapeFn that sets the output type."); } } + create_type_constraint(op, static_cast(output_count), static_cast(i), false); } diff --git a/onnxruntime/core/session/inference_session.cc b/onnxruntime/core/session/inference_session.cc index a1903898ea7f0..0cb361bae563b 100644 --- a/onnxruntime/core/session/inference_session.cc +++ b/onnxruntime/core/session/inference_session.cc @@ -38,9 +38,11 @@ #include "core/framework/utils.h" #include "core/graph/graph_viewer.h" #include "core/graph/model.h" +#include "core/graph/model_editor_api_types.h" #include "core/graph/model_saving_options.h" #include "core/optimizer/graph_transformer_utils.h" #include "core/optimizer/graph_transformer.h" +#include "core/optimizer/graph_optimizer_registry.h" #include "core/optimizer/layout_transformation/layout_transformation.h" #include "core/optimizer/insert_cast_transformer.h" #include "core/optimizer/qdq_transformer/ensure_unique_dq_for_node_unit.h" @@ -67,11 +69,11 @@ #include "core/optimizer/stft_decomposition.h" #endif #include "core/session/environment.h" -#include "core/session/user_logging_sink.h" #include "core/session/IOBinding.h" #include "core/session/inference_session_utils.h" #include "core/session/onnxruntime_session_options_config_keys.h" #include "core/session/onnxruntime_run_options_config_keys.h" +#include "core/session/user_logging_sink.h" #include "core/util/protobuf_parsing_utils.h" #include "core/util/thread_utils.h" @@ -151,7 +153,7 @@ static bool HasMemcpyNodes(const Graph& graph) { return false; } -static bool AreAllComputeNodesAssignedToCudaOrJsOrDmlEp(const Graph& graph) { +static bool AreAllComputeNodesAssignedToCudaOrJsOrDmlEpWebGpuEp(const Graph& graph) { bool nodes_on_cpu_and_cuda_and_js_and_dml_eps_only = true; for (const auto& node : graph.Nodes()) { @@ -162,6 +164,7 @@ static bool AreAllComputeNodesAssignedToCudaOrJsOrDmlEp(const Graph& graph) { !(node_provider == kCudaExecutionProvider || node_provider == kRocmExecutionProvider || node_provider == kJsExecutionProvider || + node_provider == kWebGpuExecutionProvider || node_provider == kDmlExecutionProvider) && node_provider != kCpuExecutionProvider) { nodes_on_cpu_and_cuda_and_js_and_dml_eps_only = false; @@ -381,6 +384,7 @@ void InferenceSession::ConstructorCommon(const SessionOptions& session_options, #if !defined(ORT_MINIMAL_BUILD) // Update the number of steps for the graph transformer manager using the "finalized" session options ORT_THROW_IF_ERROR(graph_transformer_mgr_.SetSteps(session_options_.max_num_graph_transformation_steps)); + graph_transformer_mgr_.SetLoadCancellationFn(this->check_load_cancellation_fn_); #endif #if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) @@ -1002,11 +1006,13 @@ common::Status InferenceSession::LoadOnnxModel(const PathString& model_uri) { std::copy(std::begin(interop_domains_), std::end(interop_domains_), std::back_inserter(domain_ptrs)); ORT_RETURN_IF_ERROR(AddCustomOpDomains(domain_ptrs)); #endif + const bool strict_shape_type_inference = session_options_.config_options.GetConfigOrDefault( kOrtSessionOptionsConfigStrictShapeTypeInference, "0") == "1"; return onnxruntime::Model::Load(model_location_, model, HasLocalSchema() ? &custom_schema_registries_ : nullptr, *session_logger_, - ModelOptions(true, strict_shape_type_inference)); + ModelOptions(true, strict_shape_type_inference, + check_load_cancellation_fn_)); }; common::Status st = LoadWithLoader(loader, "model_loading_uri"); @@ -1099,7 +1105,8 @@ common::Status InferenceSession::Load(const void* model_data, int model_data_len return onnxruntime::Model::Load(std::move(model_proto), model_location_, model, HasLocalSchema() ? &custom_schema_registries_ : nullptr, *session_logger_, - ModelOptions(true, strict_shape_type_inference)); + ModelOptions(true, strict_shape_type_inference, + check_load_cancellation_fn_)); }; return LoadWithLoader(loader, "model_loading_array"); @@ -1137,7 +1144,8 @@ common::Status InferenceSession::LoadOnnxModel(ModelProto model_proto) { // This call will move model_proto to the constructed model instance return onnxruntime::Model::Load(std::move(model_proto), model_location_, model, HasLocalSchema() ? &custom_schema_registries_ : nullptr, *session_logger_, - ModelOptions(true, strict_shape_type_inference)); + ModelOptions(true, strict_shape_type_inference, + check_load_cancellation_fn_)); }; return LoadWithLoader(loader, "model_loading_proto"); @@ -1170,7 +1178,8 @@ common::Status InferenceSession::Load(std::istream& model_istream, bool allow_re const bool strict_shape_type_inference = session_options_.config_options.GetConfigOrDefault( kOrtSessionOptionsConfigStrictShapeTypeInference, "0") == "1"; ModelOptions model_opts(allow_released_opsets_only, - strict_shape_type_inference); + strict_shape_type_inference, + check_load_cancellation_fn_); std::string external_data_folder_path = session_options_.config_options.GetConfigOrDefault( kOrtSessionOptionsModelExternalInitializersFileFolderPath, ""); @@ -1209,12 +1218,64 @@ common::Status InferenceSession::Load() { // Pass on ownership of the parsed ModelProto to the Model instance (its job here is done by this stage) return Model::Load(std::move(this->model_proto_), model_location_, model, HasLocalSchema() ? &custom_schema_registries_ : nullptr, *session_logger_, - ModelOptions(allow_released_opsets_only, strict_shape_type_inference)); + ModelOptions(allow_released_opsets_only, strict_shape_type_inference, + check_load_cancellation_fn_)); }; return LoadWithLoader(loader, "model_loading_from_saved_proto"); } +common::Status InferenceSession::Load(const OrtModel& model_editor_api_model) { + std::lock_guard l(session_mutex_); + + if (is_model_loaded_) { // already loaded + Status status(common::ONNXRUNTIME, common::MODEL_LOADED, "This session already contains a loaded model."); + LOGS(*session_logger_, ERROR) << status.ErrorMessage(); + return status; + } + + if (is_inited_) { + Status status(common::ONNXRUNTIME, common::MODEL_LOADED, "This session has already been initialized."); + LOGS(*session_logger_, ERROR) << status.ErrorMessage(); + return status; + } + + const bool strict_shape_type_inference = session_options_.config_options.GetConfigOrDefault( + kOrtSessionOptionsConfigStrictShapeTypeInference, "0") == "1"; + + // need to go from unique_ptr to shared_ptr when moving into model_ + std::unique_ptr tmp_model; + ORT_RETURN_IF_ERROR(Model::LoadFromModelEditorApiModel(model_editor_api_model, + HasLocalSchema() ? &custom_schema_registries_ : nullptr, + ModelOptions(true, strict_shape_type_inference, + check_load_cancellation_fn_), + *session_logger_, tmp_model)); + + model_ = std::move(tmp_model); + + is_model_loaded_ = true; + + return Status::OK(); +} + +common::Status InferenceSession::ApplyUpdates(const OrtModel& model_editor_api_model) { + std::lock_guard l(session_mutex_); + + if (!is_model_loaded_) { + Status status(common::ONNXRUNTIME, common::MODEL_LOADED, "This session does not contain a loaded model."); + LOGS(*session_logger_, ERROR) << status.ErrorMessage(); + return status; + } + + if (is_inited_) { + Status status(common::ONNXRUNTIME, common::MODEL_LOADED, "This session has already been initialized."); + LOGS(*session_logger_, ERROR) << status.ErrorMessage(); + return status; + } + + return model_->MainGraph().UpdateUsingModelEditorApiModel(model_editor_api_model); +} + common::Status InferenceSession::TransformGraph(onnxruntime::Graph& graph, bool saving_model_in_ort_format) { // The transformer order: // 1. Ensure we inline as many functions as possible. We refer to it as Ahead Of Time (AOT) function inlining. @@ -1227,8 +1288,14 @@ common::Status InferenceSession::TransformGraph(onnxruntime::Graph& graph, bool // 6. insert cast nodes (required transformer). // 7. insert copy nodes (required transformer). + // Create GraphOptimizerRegistry instance for providing predefined graph optimizers and selection functions for EPs to lookup + auto graph_optimizer_registry = std::make_unique(&session_options_, + execution_providers_.Get(onnxruntime::kCpuExecutionProvider), + session_logger_); + GraphPartitioner partitioner(kernel_registry_manager_, execution_providers_, std::move(graph_optimizer_registry), + check_load_cancellation_fn_); + // Run Ahead Of time function inlining - GraphPartitioner partitioner(kernel_registry_manager_, execution_providers_); if (const bool disable_aot_function_inlining = session_options_.config_options.GetConfigOrDefault( kOrtSessionOptionsDisableAheadOfTimeFunctionInlining, "0") == "1"; @@ -1631,7 +1698,7 @@ Status PartitionOrtFormatModel(onnxruntime::Graph& graph, const ExecutionProviders& providers, KernelRegistryManager& kernel_registry_manager, SessionState& session_state, - const ConfigOptions& config_options, + const SessionOptions& sess_options, const logging::Logger& logger) { layout_transformation::TransformLayoutFunction transform_layout_fn = nullptr; @@ -1649,11 +1716,17 @@ Status PartitionOrtFormatModel(onnxruntime::Graph& graph, } #endif // !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) - GraphPartitioner partitioner(kernel_registry_manager, providers); + // Create GraphOptimizerRegistry instance for providing predefined graph optimizers and selection functions for EPs to lookup + auto graph_optimizer_registry = std::make_unique(&sess_options, + providers.Get(onnxruntime::kCpuExecutionProvider), + &logger); + + GraphPartitioner partitioner(kernel_registry_manager, providers, std::move(graph_optimizer_registry), + [&sess_options]() -> bool { return sess_options.IsLoadCancellationFlagSet(); }); ORT_RETURN_IF_ERROR(partitioner.Partition(graph, session_state.GetMutableFuncMgr(), transform_layout_fn, - config_options, + sess_options.config_options, logger, GraphPartitioner::Mode::kOrtFormatLoad)); @@ -1722,6 +1795,11 @@ common::Status InferenceSession::HasInvalidCombinationOfExecutionProviders() con #pragma warning(disable : 26117) #endif common::Status InferenceSession::Initialize() { + if (session_options_.IsLoadCancellationFlagSet()) { + return ORT_MAKE_STATUS(ONNXRUNTIME, MODEL_LOAD_CANCELED, + "Session initialization canceled due to user request."); + } + Status status = Status::OK(); TimePoint tp; if (session_profiler_.IsEnabled()) { @@ -1947,6 +2025,10 @@ common::Status InferenceSession::Initialize() { // now that all the transforms are done, call Resolve on the main graph. this will recurse into the subgraphs. ORT_RETURN_IF_ERROR_SESSIONID_(graph.Resolve()); + if (session_options_.IsLoadCancellationFlagSet()) { + return ORT_MAKE_STATUS(ONNXRUNTIME, MODEL_LOAD_CANCELED, + "Session initialization canceled due to user request."); + } // Currently graph capture is only considered by CUDA EP, TRT EP, ROCM EP and JS EP. // @@ -1979,6 +2061,7 @@ common::Status InferenceSession::Initialize() { onnxruntime::kCudaExecutionProvider, onnxruntime::kRocmExecutionProvider, onnxruntime::kJsExecutionProvider, + onnxruntime::kWebGpuExecutionProvider, onnxruntime::kDmlExecutionProvider}; for (auto& it : graph_support_ep_list) { @@ -2001,12 +2084,13 @@ common::Status InferenceSession::Initialize() { if (strcmp(target_ep->Type().c_str(), onnxruntime::kCudaExecutionProvider) == 0 || strcmp(target_ep->Type().c_str(), onnxruntime::kRocmExecutionProvider) == 0 || strcmp(target_ep->Type().c_str(), onnxruntime::kJsExecutionProvider) == 0 || + strcmp(target_ep->Type().c_str(), onnxruntime::kWebGpuExecutionProvider) == 0 || strcmp(target_ep->Type().c_str(), onnxruntime::kDmlExecutionProvider) == 0) { // Ensure that all nodes have been partitioned to CUDA/JS or CPU EP && there are no memcpy nodes // The reasoning behind this logic is that certain shape nodes will be forced onto CPU // and as long as there are no memcpy nodes this is confirmation that no compute nodes have been placed on the CPU EP // which is all we care about. - if (!AreAllComputeNodesAssignedToCudaOrJsOrDmlEp(graph)) { + if (!AreAllComputeNodesAssignedToCudaOrJsOrDmlEpWebGpuEp(graph)) { LOGS(*session_logger_, ERROR) << "This session cannot use the graph capture feature as requested by the user " << " as all compute graph nodes have not been partitioned to the " << target_ep->Type(); @@ -2096,7 +2180,7 @@ common::Status InferenceSession::Initialize() { #endif // !defined(ORT_MINIMAL_BUILD) } else { ORT_RETURN_IF_ERROR_SESSIONID_(PartitionOrtFormatModel(graph, execution_providers_, kernel_registry_manager_, - *session_state_, session_options_.config_options, *session_logger_)); + *session_state_, session_options_, *session_logger_)); #if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) const auto& cpu_ep = *execution_providers_.Get(onnxruntime::kCpuExecutionProvider); @@ -3336,6 +3420,10 @@ common::Status InferenceSession::WaitForNotification(Notification* p_executor_do return Status::OK(); } +const Model& InferenceSession::GetModel() const { + return *model_; +} + SessionIOBinding::SessionIOBinding(InferenceSession* session) : sess_(session) { ORT_ENFORCE(session->NewIOBinding(&binding_).IsOK()); } diff --git a/onnxruntime/core/session/inference_session.h b/onnxruntime/core/session/inference_session.h index 2c0c09dfd3e51..7b5d98c38a0fa 100644 --- a/onnxruntime/core/session/inference_session.h +++ b/onnxruntime/core/session/inference_session.h @@ -47,6 +47,9 @@ namespace ONNX_NAMESPACE { class ModelProto; } // namespace ONNX_NAMESPACE +// OrtModelEditorApi Model. Used to dynamically construct a model via C API at runtime. +struct OrtModel; + namespace onnxruntime { // forward declarations class CustomRegistry; class Environment; @@ -320,6 +323,27 @@ class InferenceSession { * @return OK if success. */ [[nodiscard]] common::Status Load(); + + /** + * Load an OrtModel that was dynamically constructed via OrtModelEditorApi. + * + * @param graph_api_model OrtModel from OrtModelEditorApi + * @return OK if success. + */ + [[nodiscard]] common::Status Load(const OrtModel& graph_api_model); + + /** + * Apply updates from an OrtModel that was created via OrtModelEditorApi. + * This can: + * - add nodes at the start and end of the model + * - add initializers + * - update the graph inputs/outputs + * + * @param graph_api_model OrtModel from OrtModelEditorApi + * @return OK if success. + */ + [[nodiscard]] common::Status ApplyUpdates(const OrtModel& graph_api_model); + #endif // !defined(ORT_MINIMAL_BUILD) /** @@ -571,6 +595,8 @@ class InferenceSession { #endif + const Model& GetModel() const; + protected: #if !defined(ORT_MINIMAL_BUILD) @@ -627,6 +653,12 @@ class InferenceSession { /// convenience pointer to logger. should always be the same as session_state_.Logger(); const logging::Logger* session_logger_; + // The list of execution providers. + // This MUST be prior to model_ in case there are values in the model that were allocated using an allocator + // provided by the EP. If that is the case the allocator's `free` implementation may depend on other parts of the + // EP instance. + ExecutionProviders execution_providers_; + // The model served by this inference session instance. // Currently this has to be a shared ptr because the Model::Load method // returns a shared_ptr only. Ideally factory functions should always return @@ -637,9 +669,6 @@ class InferenceSession { // The file path of where the model was loaded. e.g. /tmp/test_squeezenet/model.onnx PathString model_location_; - // The list of execution providers. - ExecutionProviders execution_providers_; - private: ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(InferenceSession); void SetLoggingManager(const SessionOptions& session_options, @@ -752,6 +781,10 @@ class InferenceSession { // the session options are released after the individual operators are destroyed. SessionOptions session_options_; + CheckLoadCancellationFn check_load_cancellation_fn_ = [this]() { + return session_options_.IsLoadCancellationFlagSet(); + }; + /// Logging manager if provided. logging::LoggingManager* logging_manager_; diff --git a/onnxruntime/core/session/model_editor_api.h b/onnxruntime/core/session/model_editor_api.h new file mode 100644 index 0000000000000..71004866bc867 --- /dev/null +++ b/onnxruntime/core/session/model_editor_api.h @@ -0,0 +1,65 @@ +namespace OrtModelEditorAPI { + +// implementation that returns the API struct +ORT_API(const OrtModelEditorApi*, GetModelEditorApi); + +// APIs to create/edit type info +ORT_API_STATUS_IMPL(CreateTensorTypeInfo, _In_ const OrtTensorTypeAndShapeInfo* tensor_info, + _Out_ OrtTypeInfo** type_info); +ORT_API_STATUS_IMPL(CreateSparseTensorTypeInfo, _In_ const OrtTensorTypeAndShapeInfo* tensor_info, + _Out_ OrtTypeInfo** type_info); +ORT_API_STATUS_IMPL(CreateMapTypeInfo, ONNXTensorElementDataType map_key_type, _In_ const OrtTypeInfo* map_value_type, + _Out_ OrtTypeInfo** type_info); +ORT_API_STATUS_IMPL(CreateSequenceTypeInfo, _In_ const OrtTypeInfo* sequence_type, _Out_ OrtTypeInfo** type_info); +ORT_API_STATUS_IMPL(CreateOptionalTypeInfo, _In_ const OrtTypeInfo* contained_type, _Out_ OrtTypeInfo** type_info); + +ORT_API_STATUS_IMPL(CreateValueInfo, _In_ const char* name, _In_ const OrtTypeInfo* type_info, + _Outptr_ OrtValueInfo** value_info); + +ORT_API_STATUS_IMPL(CreateNode, const char* operator_name, const char* domain_name, _In_ const char* node_name, + _In_reads_(input_names_len) const char* const* input_names, size_t input_names_len, + _In_reads_(output_names_len) const char* const* output_names, size_t output_names_len, + _In_reads_(attribs_len) _Inout_opt_ OrtOpAttr** attributes, _In_opt_ size_t attribs_len, + _Outptr_ OrtNode** node); + +ORT_API_STATUS_IMPL(CreateGraph, _Outptr_ OrtGraph** graph); +ORT_API_STATUS_IMPL(SetGraphInputs, _In_ OrtGraph* graph, + _In_reads_(inputs_len) _In_ OrtValueInfo** inputs, _In_ size_t inputs_len); +ORT_API_STATUS_IMPL(SetGraphOutputs, _In_ OrtGraph* graph, + _In_reads_(outputs_len) _In_ OrtValueInfo** outputs, _In_ size_t outputs_len); +ORT_API_STATUS_IMPL(AddInitializerToGraph, _In_ OrtGraph* graph, _In_ const char* name, _Inout_ OrtValue* tensor, + bool data_is_external); +ORT_API_STATUS_IMPL(AddNodeToGraph, _In_ OrtGraph* graph, _Inout_ OrtNode* node); + +ORT_API_STATUS_IMPL(CreateModel, + _In_reads_(opset_entries_len) const char* const* domain_names, + _In_reads_(opset_entries_len) const int* opset_versions, + size_t opset_entries_len, + _Outptr_ OrtModel** model); +ORT_API_STATUS_IMPL(AddGraphToModel, _In_ OrtModel* model, _Inout_ OrtGraph* graph); + +ORT_API_STATUS_IMPL(CreateSessionFromModel, _In_ const OrtEnv* env, _In_ const OrtModel* model, + _In_ const OrtSessionOptions* options, _Outptr_ OrtSession** out); + +// +// Model editing APIs for updating existing model by adding node/s at start or end. +// +ORT_API_STATUS_IMPL(CreateModelEditorSession, _In_ const OrtEnv* env, + _In_ const ORTCHAR_T* model_path, + _In_ const OrtSessionOptions* options, + _Outptr_ OrtSession** out); + +ORT_API_STATUS_IMPL(CreateModelEditorSessionFromArray, _In_ const OrtEnv* env, + _In_ const void* model_data, size_t model_data_length, + _In_ const OrtSessionOptions* options, + _Outptr_ OrtSession** out); + +ORT_API_STATUS_IMPL(SessionGetOpsetForDomain, _In_ const OrtSession* session, _In_ const char* domain, + _Out_ int* opset); + +ORT_API_STATUS_IMPL(ApplyModelToModelEditorSession, _In_ OrtSession* session, _In_ OrtModel* model); + +ORT_API_STATUS_IMPL(FinalizeModelEditorSession, _In_ OrtSession* session, _In_ const OrtSessionOptions* options, + _Inout_ OrtPrepackedWeightsContainer* prepacked_weights_container); + +} // namespace OrtModelEditorAPI diff --git a/onnxruntime/core/session/model_editor_c_api.cc b/onnxruntime/core/session/model_editor_c_api.cc new file mode 100644 index 0000000000000..2f09b903ed941 --- /dev/null +++ b/onnxruntime/core/session/model_editor_c_api.cc @@ -0,0 +1,358 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include + +#include "core/framework/error_code_helper.h" +#include "core/framework/ort_value.h" +#include "core/framework/onnxruntime_typeinfo.h" +#include "core/framework/tensor_type_and_shape.h" +#include "core/graph/constants.h" +#include "core/graph/model.h" +#include "core/graph/model_editor_api_types.h" +#include "core/graph/onnx_protobuf.h" +#include "core/session/abi_session_options_impl.h" +#include "core/session/inference_session.h" +#include "core/session/model_editor_api.h" +#include "core/session/ort_apis.h" +#include "core/session/ort_env.h" +#include "core/session/utils.h" + +using namespace onnxruntime; + +ORT_API_STATUS_IMPL(OrtModelEditorAPI::CreateValueInfo, _In_ const char* name, _In_ const OrtTypeInfo* type_info, + _Outptr_ OrtValueInfo** value_info) { + API_IMPL_BEGIN + if (name == nullptr || *name == '\0') { + return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, "name cannot be null or empty string"); + } + + if (type_info == nullptr) { + return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, "type_info cannot be null"); + } + + if (type_info->type != ONNX_TYPE_TENSOR) { + return OrtApis::CreateStatus(ORT_FAIL, "Only tensor types are supported currently"); + } + + if (type_info->tensor_type_info == nullptr) { + return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, "tensor_type_info cannot be null"); + } + + auto vi = std::make_unique(); + vi->name = name; + vi->type_info = type_info->Clone(); + + *value_info = vi.release(); + + return nullptr; + API_IMPL_END +} + +ORT_API_STATUS_IMPL(OrtModelEditorAPI::CreateNode, const char* operator_name, const char* domain_name, + _In_ const char* node_name, + _In_reads_(input_names_len) const char* const* input_names, size_t input_names_len, + _In_reads_(output_names_len) const char* const* output_names, size_t output_names_len, + _In_reads_(attribs_len) _Inout_opt_ OrtOpAttr** attributes, _In_opt_ size_t attribs_len, + _Outptr_ OrtNode** node) { + API_IMPL_BEGIN + auto n = std::make_unique(); + n->operator_name = operator_name; + n->domain_name = domain_name == kOnnxDomainAlias ? kOnnxDomain : domain_name; + n->node_name = node_name; + + n->input_names.reserve(input_names_len); + for (size_t i = 0; i < input_names_len; ++i) { + n->input_names.push_back(input_names[i]); + } + + n->output_names.reserve(output_names_len); + for (size_t i = 0; i < output_names_len; ++i) { + n->output_names.push_back(output_names[i]); + } + + if (attributes != nullptr) { + n->attributes.reserve(attribs_len); + for (size_t i = 0; i < attribs_len; ++i) { + n->attributes.push_back(*reinterpret_cast(attributes[i])); + // take ownership. as we took a copy that means releasing the original value + OrtApis::ReleaseOpAttr(attributes[i]); + attributes[i] = nullptr; + } + } + + *node = n.release(); + return nullptr; + API_IMPL_END +} + +ORT_API_STATUS_IMPL(OrtModelEditorAPI::CreateGraph, _Outptr_ OrtGraph** graph) { + API_IMPL_BEGIN + auto g = std::make_unique(); + + // do some reserves to reduce reallocation. if we had a hint about sizes upfront that would be optimal + g->initializers.reserve(32); + g->external_initializers.reserve(32); + g->nodes.reserve(64); + + *graph = g.release(); + return nullptr; + API_IMPL_END +} + +ORT_API_STATUS_IMPL(OrtModelEditorAPI::SetGraphInputs, _In_ OrtGraph* graph, + _In_reads_(inputs_len) _In_ OrtValueInfo** inputs, _In_ size_t inputs_len) { + API_IMPL_BEGIN + graph->inputs.clear(); + for (size_t i = 0; i < inputs_len; ++i) { + if (inputs[i] == nullptr) { + return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, "inputs cannot contain null entries"); + } + + graph->inputs.push_back(std::unique_ptr(inputs[i])); // take ownership + inputs[i] = nullptr; + } + + return nullptr; + API_IMPL_END +} + +ORT_API_STATUS_IMPL(OrtModelEditorAPI::SetGraphOutputs, _In_ OrtGraph* graph, + _In_reads_(outputs_len) _In_ OrtValueInfo** outputs, _In_ size_t outputs_len) { + API_IMPL_BEGIN + graph->outputs.clear(); + for (size_t i = 0; i < outputs_len; ++i) { + if (outputs[i] == nullptr) { + return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, "outputs cannot contain null entries"); + } + + graph->outputs.push_back(std::unique_ptr(outputs[i])); // take ownership + outputs[i] = nullptr; + } + + return nullptr; + API_IMPL_END +} + +ORT_API_STATUS_IMPL(OrtModelEditorAPI::AddInitializerToGraph, _In_ OrtGraph* graph, _In_ const char* name, + _Inout_ OrtValue* tensor, bool data_is_external) { + API_IMPL_BEGIN + if (!tensor->IsTensor()) { + return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, "Only Tensor is currently supported."); + } + + if (!tensor->IsAllocated()) { + return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, "Tensor must be allocated."); + } + + const auto& t = tensor->Get(); + if (t.Location().device.Type() != OrtDevice::CPU) { + return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, "Only CPU based tensors are currently supported."); + } + + if (data_is_external) { + // enforce that an external initializer is not used if the data size is < 128 bytes. + // the reason for this is to avoid potential shape inferencing errors if this initializer is providing an + // input involved in that. the ONNX shape inferencing does not support external data for those values. + // e.g. Reshape's `shape` input, Reduce's `axes', Slice's `starts`, `ends`, `steps`, Clip's `min`, `max`, etc. + if (t.SizeInBytes() < 128) { + return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, + "External initializer should only be used for data >= 128 bytes. " + "Please use CreateTensorAsOrtValue instead."); + } + + graph->external_initializers[name] = std::unique_ptr(tensor); // take ownership + } else { + graph->initializers[name] = std::unique_ptr(tensor); // take ownership + } + + return nullptr; + API_IMPL_END +} + +ORT_API_STATUS_IMPL(OrtModelEditorAPI::AddNodeToGraph, _In_ OrtGraph* graph, _Inout_ OrtNode* node) { + API_IMPL_BEGIN + graph->nodes.push_back(std::unique_ptr(node)); // take ownership + return nullptr; + API_IMPL_END +} + +ORT_API_STATUS_IMPL(OrtModelEditorAPI::CreateModel, + _In_reads_(opset_entries_len) const char* const* domain_names, + _In_reads_(opset_entries_len) const int* opset_versions, + size_t opset_entries_len, + _Outptr_ OrtModel** model) { + API_IMPL_BEGIN + auto m = std::make_unique(); + for (size_t i = 0; i < opset_entries_len; ++i) { + m->domain_to_version[domain_names[i]] = opset_versions[i]; + } + + *model = m.release(); + return nullptr; + API_IMPL_END +} + +ORT_API_STATUS_IMPL(OrtModelEditorAPI::AddGraphToModel, _In_ OrtModel* model, _Inout_ OrtGraph* graph) { + API_IMPL_BEGIN + + if (graph == nullptr) { + return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, "graph cannot be null"); + } + + model->graph = std::unique_ptr(graph); // take ownership + return nullptr; + API_IMPL_END +} + +ORT_API_STATUS_IMPL(OrtModelEditorAPI::CreateSessionFromModel, _In_ const OrtEnv* env, _In_ const OrtModel* model, + _In_ const OrtSessionOptions* options, _Outptr_ OrtSession** out) { + API_IMPL_BEGIN + + std::unique_ptr sess; + OrtStatus* status = nullptr; + *out = nullptr; + + ORT_TRY { + sess = std::make_unique( + options == nullptr ? onnxruntime::SessionOptions() : options->value, + env->GetEnvironment()); + + ORT_API_RETURN_IF_STATUS_NOT_OK(sess->Load(*model)); + + ORT_API_RETURN_IF_ERROR(InitializeSession(options, *sess)); + + *out = reinterpret_cast(sess.release()); + } + ORT_CATCH(const std::exception& e) { + ORT_HANDLE_EXCEPTION([&]() { + status = OrtApis::CreateStatus(ORT_FAIL, e.what()); + }); + } + + return status; + + API_IMPL_END +} + +ORT_API_STATUS_IMPL(OrtModelEditorAPI::CreateModelEditorSession, + _In_ const OrtEnv* env, _In_ const ORTCHAR_T* model_path, _In_ const OrtSessionOptions* options, + _Outptr_ OrtSession** out) { + API_IMPL_BEGIN + std::unique_ptr session; + OrtStatus* status = nullptr; + *out = nullptr; + + ORT_TRY { + ORT_API_RETURN_IF_ERROR(CreateSessionAndLoadModel(options, env, model_path, nullptr, 0, session)); + *out = reinterpret_cast(session.release()); + } + ORT_CATCH(const std::exception& e) { + ORT_HANDLE_EXCEPTION([&]() { + status = OrtApis::CreateStatus(ORT_FAIL, e.what()); + }); + } + + return status; + API_IMPL_END +} + +ORT_API_STATUS_IMPL(OrtModelEditorAPI::CreateModelEditorSessionFromArray, _In_ const OrtEnv* env, + _In_ const void* model_data, size_t model_data_length, + _In_ const OrtSessionOptions* options, + _Outptr_ OrtSession** out) { + API_IMPL_BEGIN + std::unique_ptr session; + OrtStatus* status = nullptr; + *out = nullptr; + + ORT_TRY { + ORT_API_RETURN_IF_ERROR(CreateSessionAndLoadModel(options, env, nullptr, model_data, model_data_length, session)); + *out = reinterpret_cast(session.release()); + } + ORT_CATCH(const std::exception& e) { + ORT_HANDLE_EXCEPTION([&]() { + status = OrtApis::CreateStatus(ORT_FAIL, e.what()); + }); + } + + return status; + API_IMPL_END +} + +ORT_API_STATUS_IMPL(OrtModelEditorAPI::SessionGetOpsetForDomain, _In_ const OrtSession* ort_session, + _In_ const char* domain, _Out_ int* opset) { + const auto& session = *reinterpret_cast(ort_session); + const auto& domain_opset_map = session.GetModel().MainGraph().DomainToVersionMap(); + + auto it = domain_opset_map.find(domain); + if (it == domain_opset_map.cend()) { + return OrtApis::CreateStatus(ORT_FAIL, "Domain not used by model."); + } + + *opset = it->second; + return nullptr; +} + +ORT_API_STATUS_IMPL(OrtModelEditorAPI::ApplyModelToModelEditorSession, + _In_ OrtSession* session, _In_ OrtModel* model) { + API_IMPL_BEGIN + auto sess = reinterpret_cast(session); + ORT_API_RETURN_IF_STATUS_NOT_OK(sess->ApplyUpdates(*model)); + return nullptr; + API_IMPL_END +} + +ORT_API_STATUS_IMPL(OrtModelEditorAPI::FinalizeModelEditorSession, _In_ OrtSession* session, + _In_ const OrtSessionOptions* options, + _Inout_ OrtPrepackedWeightsContainer* prepacked_weights_container) { + API_IMPL_BEGIN + auto sess = reinterpret_cast(session); + ORT_API_RETURN_IF_ERROR(InitializeSession(options, *sess, prepacked_weights_container)); + return nullptr; + API_IMPL_END +} + +static constexpr OrtModelEditorApi ort_model_editor_api = { + // NOTE: The C# bindings depend on the API order within this struct so all additions must be at the end, + // and no functions can be removed (the implementation needs to change to return an error). + + &OrtModelEditorAPI::CreateTensorTypeInfo, + &OrtModelEditorAPI::CreateSparseTensorTypeInfo, + &OrtModelEditorAPI::CreateMapTypeInfo, + &OrtModelEditorAPI::CreateSequenceTypeInfo, + &OrtModelEditorAPI::CreateOptionalTypeInfo, + + &OrtModelEditorAPI::CreateValueInfo, + + &OrtModelEditorAPI::CreateNode, + + &OrtModelEditorAPI::CreateGraph, + &OrtModelEditorAPI::SetGraphInputs, + &OrtModelEditorAPI::SetGraphOutputs, + &OrtModelEditorAPI::AddInitializerToGraph, + &OrtModelEditorAPI::AddNodeToGraph, + + &OrtModelEditorAPI::CreateModel, + &OrtModelEditorAPI::AddGraphToModel, + + &OrtModelEditorAPI::CreateSessionFromModel, + + &OrtModelEditorAPI::CreateModelEditorSession, + &OrtModelEditorAPI::CreateModelEditorSessionFromArray, + &OrtModelEditorAPI::SessionGetOpsetForDomain, + &OrtModelEditorAPI::ApplyModelToModelEditorSession, + &OrtModelEditorAPI::FinalizeModelEditorSession, +}; + +// checks that we don't violate the rule that the functions must remain in the slots they were originally assigned +static_assert(offsetof(OrtModelEditorApi, FinalizeModelEditorSession) / sizeof(void*) == 19, + "Size of version 21 API cannot change"); // initial version in ORT 1.21 + +ORT_API(const OrtModelEditorApi*, OrtModelEditorAPI::GetModelEditorApi) { + return &ort_model_editor_api; +} + +#endif // !defined(ORT_MINIMAL_BUILD) diff --git a/onnxruntime/core/session/onnxruntime_c_api.cc b/onnxruntime/core/session/onnxruntime_c_api.cc index ca6950af0227a..ac67a3ce5c1a2 100644 --- a/onnxruntime/core/session/onnxruntime_c_api.cc +++ b/onnxruntime/core/session/onnxruntime_c_api.cc @@ -1,45 +1,47 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/session/onnxruntime_c_api.h" -#include "core/session/allocator_adapters.h" -#include "core/session/inference_session_utils.h" -#include "core/session/IOBinding.h" -#include "core/framework/allocator.h" -#include "core/framework/error_code_helper.h" -#include "core/framework/execution_provider.h" -#include "core/framework/tensor_type_and_shape.h" -#include "core/framework/utils.h" #include #include #include +#include #include #include "core/common/common.h" #include "core/common/logging/logging.h" #include "core/common/narrow.h" -#include "core/common/status.h" #include "core/common/safeint.h" -#include "core/graph/constants.h" -#include "core/graph/graph.h" +#include "core/common/status.h" +#include "core/common/string_helper.h" #include "core/framework/allocator.h" -#include "core/framework/tensor.h" +#include "core/framework/allocator.h" +#include "core/framework/callback.h" +#include "core/framework/data_types.h" +#include "core/framework/error_code_helper.h" +#include "core/framework/execution_provider.h" +#include "core/framework/onnxruntime_typeinfo.h" #include "core/framework/ort_value.h" +#include "core/framework/tensor.h" +#include "core/framework/tensor_type_and_shape.h" +#include "core/framework/tensorprotoutils.h" +#include "core/framework/TensorSeq.h" +#include "core/framework/utils.h" +#include "core/graph/constants.h" +#include "core/graph/graph.h" +#include "core/graph/model_editor_api_types.h" #include "core/providers/get_execution_providers.h" +#include "core/session/abi_session_options_impl.h" +#include "core/session/allocator_adapters.h" #include "core/session/environment.h" -#include "core/framework/callback.h" -#include "core/framework/tensorprotoutils.h" -#include "core/framework/onnxruntime_typeinfo.h" #include "core/session/inference_session.h" +#include "core/session/inference_session_utils.h" +#include "core/session/IOBinding.h" +#include "core/session/lora_adapters.h" +#include "core/session/model_editor_api.h" +#include "core/session/onnxruntime_c_api.h" #include "core/session/ort_apis.h" #include "core/session/ort_env.h" -#include "core/framework/data_types.h" -#include "abi_session_options_impl.h" -#include "core/framework/TensorSeq.h" -#include -#include "core/common/string_helper.h" - -#include "core/session/lora_adapters.h" +#include "core/session/utils.h" #ifdef USE_CUDA #include "core/providers/cuda/cuda_provider_factory.h" @@ -114,6 +116,72 @@ using namespace onnxruntime; auto v = (value); \ auto tensor = v->GetMutable(); +namespace { +// Create tensor. Allocates memory. Tensor owns memory. Allocator is wrapped and stored in a shared_ptr in Tensor. +ORT_STATUS_PTR CreateTensorImpl(MLDataType ml_type, const int64_t* shape, size_t shape_len, + OrtAllocator* allocator, OrtValue& value) { + TensorShape tensor_shape(shape, shape_len); + AllocatorPtr alloc_ptr = std::make_shared(allocator); + Tensor::InitOrtValue(ml_type, tensor_shape, std::move(alloc_ptr), value); + return nullptr; +} + +// Create Tensor with existing data. Tensor does not own memory. +ORT_STATUS_PTR CreateTensorImpl(MLDataType ml_type, + const int64_t* shape, size_t shape_len, + const OrtMemoryInfo* info, + void* p_data, size_t p_data_len, + OrtValue& ort_value) { + TensorShape tensor_shape(shape, shape_len); + if (std::any_of(tensor_shape.GetDims().begin(), tensor_shape.GetDims().end(), [](int64_t v) { return v < 0; })) { + return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, "tried creating tensor with negative value in shape"); + } + + size_t size_to_allocate = 0; + Status status = Tensor::CalculateTensorStorageSize(ml_type, tensor_shape, 0 /*alignment*/, size_to_allocate); + if (!status.IsOK()) { + return ToOrtStatus(status); + } + if (size_to_allocate > p_data_len) { + std::ostringstream oss; + oss << "not enough space: expected " << size_to_allocate << ", got " << p_data_len; + return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, oss.str().c_str()); + } + + Tensor::InitOrtValue(ml_type, tensor_shape, p_data, *info, ort_value); + return nullptr; +} + +ORT_STATUS_PTR CreateTensorImpl(MLDataType ml_type, + const int64_t* shape, size_t shape_len, + OrtAllocator* deleter, + void* p_data, size_t p_data_len, + OrtValue& ort_value) { + TensorShape tensor_shape(shape, shape_len); + if (std::any_of(tensor_shape.GetDims().begin(), tensor_shape.GetDims().end(), [](int64_t v) { return v < 0; })) { + return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, "tried creating tensor with negative value in shape"); + } + + size_t size_to_allocate = 0; + Status status = Tensor::CalculateTensorStorageSize(ml_type, tensor_shape, 0 /*alignment*/, size_to_allocate); + + if (!status.IsOK()) { + return ToOrtStatus(status); + } + + if (size_to_allocate > p_data_len) { + std::ostringstream oss; + oss << "p_data_len was smaller than expected. Expected:" << size_to_allocate << " Got:" << p_data_len; + return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, oss.str().c_str()); + } + + AllocatorPtr alloc_ptr = std::make_shared(deleter); + Tensor::InitOrtValue(ml_type, tensor_shape, p_data, std::move(alloc_ptr), ort_value); + return nullptr; +} + +} // namespace + ORT_API_STATUS_IMPL(OrtApis::CreateEnvWithCustomLogger, OrtLoggingFunction logging_function, _In_opt_ void* logger_param, OrtLoggingLevel logging_level, _In_ const char* logid, _Outptr_ OrtEnv** out) { @@ -187,50 +255,6 @@ ORT_API_STATUS_IMPL(OrtApis::UpdateEnvWithCustomLogLevel, _In_ OrtEnv* ort_env, API_IMPL_END } -ORT_STATUS_PTR CreateTensorImpl(MLDataType ml_type, const int64_t* shape, size_t shape_len, - _Inout_ OrtAllocator* allocator, OrtValue& value) { - TensorShape tensor_shape(shape, shape_len); - AllocatorPtr alloc_ptr = std::make_shared(allocator); - Tensor::InitOrtValue(ml_type, tensor_shape, std::move(alloc_ptr), value); - return nullptr; -} - -ORT_STATUS_PTR CreateTensorImplForSeq(MLDataType elem_type, const int64_t* shape, size_t shape_len, Tensor& out) { - OrtAllocator* allocator; - // TODO(pranav): what allocator should be used to create the tensor here? - // for the sake of simplicity of the API using the default one here - ORT_API_RETURN_IF_ERROR(OrtApis::GetAllocatorWithDefaultOptions(&allocator)); - AllocatorPtr alloc_ptr = std::make_shared(allocator); - TensorShape tensor_shape(shape, shape_len); - out = Tensor(elem_type, tensor_shape, std::move(alloc_ptr)); - return nullptr; -} - -/** - * - * this function will create a copy of the allocator info - */ -ORT_STATUS_PTR CreateTensorImpl(MLDataType ml_type, const int64_t* shape, size_t shape_len, const OrtMemoryInfo* info, - void* p_data, size_t p_data_len, OrtValue& ort_value) { - TensorShape tensor_shape(shape, shape_len); - if (std::any_of(tensor_shape.GetDims().begin(), tensor_shape.GetDims().end(), [](int64_t v) { return v < 0; })) { - return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, "tried creating tensor with negative value in shape"); - } - - size_t size_to_allocate = 0; - Status status = Tensor::CalculateTensorStorageSize(ml_type, tensor_shape, 0 /*alignment*/, size_to_allocate); - if (!status.IsOK()) { - return ToOrtStatus(status); - } - if (size_to_allocate > p_data_len) { - std::ostringstream oss; - oss << "not enough space: expected " << size_to_allocate << ", got " << p_data_len; - return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, oss.str().c_str()); - } - Tensor::InitOrtValue(ml_type, tensor_shape, p_data, *info, ort_value); - return nullptr; -} - ORT_API_STATUS_IMPL(OrtApis::CreateTensorWithDataAsOrtValue, _In_ const OrtMemoryInfo* info, _Inout_ void* p_data, size_t p_data_len, _In_ const int64_t* shape, size_t shape_len, ONNXTensorElementDataType type, _Outptr_ OrtValue** out) { @@ -243,6 +267,20 @@ ORT_API_STATUS_IMPL(OrtApis::CreateTensorWithDataAsOrtValue, _In_ const OrtMemor API_IMPL_END } +ORT_API_STATUS_IMPL(OrtApis::CreateTensorWithDataAndDeleterAsOrtValue, _In_ OrtAllocator* deleter, + _In_ void* p_data, size_t p_data_len, + _In_ const int64_t* shape, size_t shape_len, + ONNXTensorElementDataType type, + _Outptr_ OrtValue** out) { + API_IMPL_BEGIN + auto ml_type = DataTypeImpl::TensorTypeFromONNXEnum(type)->GetElementType(); + auto value = std::make_unique(); + ORT_API_RETURN_IF_ERROR(CreateTensorImpl(ml_type, shape, shape_len, deleter, p_data, p_data_len, *value)); + *out = value.release(); + return nullptr; + API_IMPL_END +} + ORT_API_STATUS_IMPL(OrtApis::CreateTensorAsOrtValue, _Inout_ OrtAllocator* allocator, _In_ const int64_t* shape, size_t shape_len, ONNXTensorElementDataType type, _Outptr_ OrtValue** out) { @@ -678,117 +716,15 @@ ORT_API_STATUS_IMPL(OrtApis::EnableOrtCustomOps, _Inout_ OrtSessionOptions* opti API_IMPL_END } -namespace { -// provider either model_path, or modal_data + model_data_length. -static ORT_STATUS_PTR CreateSessionAndLoadModel(_In_ const OrtSessionOptions* options, - _In_ const OrtEnv* env, - _In_opt_z_ const ORTCHAR_T* model_path, - _In_opt_ const void* model_data, - size_t model_data_length, - std::unique_ptr& sess) { - // quick check here to decide load path. InferenceSession will provide error message for invalid values. - // TODO: Could move to a helper - const Env& os_env = Env::Default(); // OS environment (!= ORT environment) - bool load_config_from_model = - os_env.GetEnvironmentVar(inference_session_utils::kOrtLoadConfigFromModelEnvVar) == "1"; - - if (load_config_from_model) { -#if !defined(ORT_MINIMAL_BUILD) - if (model_path != nullptr) { - sess = std::make_unique( - options == nullptr ? onnxruntime::SessionOptions() : options->value, - env->GetEnvironment(), - model_path); - } else { - sess = std::make_unique( - options == nullptr ? onnxruntime::SessionOptions() : options->value, - env->GetEnvironment(), - model_data, static_cast(model_data_length)); - } -#else - return OrtApis::CreateStatus(ORT_FAIL, "Loading config from ONNX models is not supported in this build."); -#endif - } else { - sess = std::make_unique( - options == nullptr ? onnxruntime::SessionOptions() : options->value, - env->GetEnvironment()); - } - -#if !defined(ORT_MINIMAL_BUILD) || defined(ORT_MINIMAL_BUILD_CUSTOM_OPS) - // Add custom domains - if (options && !options->custom_op_domains_.empty()) { - ORT_API_RETURN_IF_STATUS_NOT_OK(sess->AddCustomOpDomains(options->custom_op_domains_)); - } -#endif - - // Finish load - if (load_config_from_model) { -#if !defined(ORT_MINIMAL_BUILD) - ORT_API_RETURN_IF_STATUS_NOT_OK(sess->Load()); -#endif - } else { - if (model_path != nullptr) { - ORT_API_RETURN_IF_STATUS_NOT_OK(sess->Load(model_path)); - } else { - ORT_API_RETURN_IF_STATUS_NOT_OK(sess->Load(model_data, static_cast(model_data_length))); - } - } - - return nullptr; -} - -static ORT_STATUS_PTR InitializeSession(_In_ const OrtSessionOptions* options, - _In_ std::unique_ptr<::onnxruntime::InferenceSession>& sess, - _Inout_opt_ OrtPrepackedWeightsContainer* prepacked_weights_container = nullptr) { - // we need to disable mem pattern if DML is one of the providers since DML doesn't have the concept of - // byte addressable memory - std::vector> provider_list; - if (options) { - for (auto& factory : options->provider_factories) { - auto provider = factory->CreateProvider(); - provider_list.push_back(std::move(provider)); - } - } - - // register the providers - for (auto& provider : provider_list) { - if (provider) { - ORT_API_RETURN_IF_STATUS_NOT_OK(sess->RegisterExecutionProvider(std::move(provider))); - } - } - - if (prepacked_weights_container != nullptr) { - ORT_API_RETURN_IF_STATUS_NOT_OK(sess->AddPrePackedWeightsContainer( - reinterpret_cast(prepacked_weights_container))); - } - - ORT_API_RETURN_IF_STATUS_NOT_OK(sess->Initialize()); - - return nullptr; -} - -} // namespace - ORT_API_STATUS_IMPL(OrtApis::CreateSession, _In_ const OrtEnv* env, _In_ const ORTCHAR_T* model_path, _In_ const OrtSessionOptions* options, _Outptr_ OrtSession** out) { API_IMPL_BEGIN std::unique_ptr sess; - OrtStatus* status = nullptr; *out = nullptr; - - ORT_TRY { - ORT_API_RETURN_IF_ERROR(CreateSessionAndLoadModel(options, env, model_path, nullptr, 0, sess)); - ORT_API_RETURN_IF_ERROR(InitializeSession(options, sess)); - - *out = reinterpret_cast(sess.release()); - } - ORT_CATCH(const std::exception& e) { - ORT_HANDLE_EXCEPTION([&]() { - status = OrtApis::CreateStatus(ORT_FAIL, e.what()); - }); - } - - return status; + ORT_API_RETURN_IF_ERROR(CreateSessionAndLoadModel(options, env, model_path, nullptr, 0, sess)); + ORT_API_RETURN_IF_ERROR(InitializeSession(options, *sess)); + *out = reinterpret_cast(sess.release()); + return nullptr; API_IMPL_END } @@ -796,22 +732,10 @@ ORT_API_STATUS_IMPL(OrtApis::CreateSessionFromArray, _In_ const OrtEnv* env, _In size_t model_data_length, _In_ const OrtSessionOptions* options, _Outptr_ OrtSession** out) { API_IMPL_BEGIN std::unique_ptr sess; - OrtStatus* status = nullptr; - *out = nullptr; - - ORT_TRY { - ORT_API_RETURN_IF_ERROR(CreateSessionAndLoadModel(options, env, nullptr, model_data, model_data_length, sess)); - ORT_API_RETURN_IF_ERROR(InitializeSession(options, sess)); - - *out = reinterpret_cast(sess.release()); - } - ORT_CATCH(const std::exception& e) { - ORT_HANDLE_EXCEPTION([&]() { - status = OrtApis::CreateStatus(ORT_FAIL, e.what()); - }); - } - - return status; + ORT_API_RETURN_IF_ERROR(CreateSessionAndLoadModel(options, env, nullptr, model_data, model_data_length, sess)); + ORT_API_RETURN_IF_ERROR(InitializeSession(options, *sess)); + *out = reinterpret_cast(sess.release()); + return nullptr; API_IMPL_END } @@ -1208,7 +1132,6 @@ ORT_API_STATUS_IMPL(OrtApis::GetResizedStringTensorElementBuffer, _Inout_ OrtVal } namespace { - OrtStatusPtr GetTensorStringSpan(const ::OrtValue& v, gsl::span& span) { if (!v.IsAllocated()) { return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, "OrtValue should contain a Tensor or a Sparse Tensor"); @@ -2112,7 +2035,6 @@ ORT_API_STATUS_IMPL(OrtApis::GetOpaqueValue, _In_ const char* domain_name, _In_ } namespace { - struct ProviderBuffer { char** buffer_; char* next_write_; @@ -2342,7 +2264,7 @@ ORT_API_STATUS_IMPL(OrtApis::CreateSessionWithPrepackedWeightsContainer, _In_ co ORT_TRY { ORT_API_RETURN_IF_ERROR(CreateSessionAndLoadModel(options, env, model_path, nullptr, 0, sess)); - ORT_API_RETURN_IF_ERROR(InitializeSession(options, sess, prepacked_weights_container)); + ORT_API_RETURN_IF_ERROR(InitializeSession(options, *sess, prepacked_weights_container)); *out = reinterpret_cast(sess.release()); } @@ -2368,7 +2290,7 @@ ORT_API_STATUS_IMPL(OrtApis::CreateSessionFromArrayWithPrepackedWeightsContainer ORT_TRY { ORT_API_RETURN_IF_ERROR(CreateSessionAndLoadModel(options, env, nullptr, model_data, model_data_length, sess)); - ORT_API_RETURN_IF_ERROR(InitializeSession(options, sess, prepacked_weights_container)); + ORT_API_RETURN_IF_ERROR(InitializeSession(options, *sess, prepacked_weights_container)); *out = reinterpret_cast(sess.release()); } @@ -2410,6 +2332,39 @@ ORT_API_STATUS_IMPL(OrtApis::SessionOptionsSetCustomJoinThreadFn, _Inout_ OrtSes API_IMPL_END } +ORT_API(void, OrtApis::ReleaseValueInfo, _Frees_ptr_opt_ OrtValueInfo* value_info) { + delete value_info; +} + +ORT_API(void, OrtApis::ReleaseNode, _Frees_ptr_opt_ OrtNode* node) { + delete node; +} + +ORT_API(void, OrtApis::ReleaseGraph, _Frees_ptr_opt_ OrtGraph* graph) { + delete graph; +} + +ORT_API(void, OrtApis::ReleaseModel, _Frees_ptr_opt_ OrtModel* model) { + delete model; +} + +ORT_API_STATUS_IMPL(OrtApis::GetValueInfoName, _In_ const OrtValueInfo* value_info, + _Out_ const char** name) { + API_IMPL_BEGIN + *name = value_info->name.c_str(); + return nullptr; + API_IMPL_END +} +ORT_API_STATUS_IMPL(OrtApis::GetValueInfoTypeInfo, _In_ const OrtValueInfo* value_info, + _Outptr_ const OrtTypeInfo** type_info) { + API_IMPL_BEGIN + + *type_info = value_info->type_info.get(); + + return nullptr; + API_IMPL_END +} + ORT_API(const OrtTrainingApi*, OrtApis::GetTrainingApi, uint32_t version) { #ifdef ENABLE_TRAINING_APIS if (version >= 13 && version <= ORT_API_VERSION) @@ -2419,13 +2374,21 @@ ORT_API(const OrtTrainingApi*, OrtApis::GetTrainingApi, uint32_t version) { version, ORT_API_VERSION); return nullptr; #else - ORT_UNUSED_PARAMETER(version); return nullptr; #endif } +ORT_API(const OrtModelEditorApi*, OrtApis::GetModelEditorApi) { +#if !defined(ORT_MINIMAL_BUILD) + return OrtModelEditorAPI::GetModelEditorApi(); +#else + fprintf(stderr, "The Model Editor API is not supported in a minimal build.\n"); + return nullptr; +#endif +} + static constexpr OrtApiBase ort_api_base = { &OrtApis::GetApi, &OrtApis::GetVersionString}; @@ -2469,7 +2432,7 @@ Second example, if we wanted to add and remove some members, we'd do this: In GetApi we now make it return ort_api_3 for version 3. */ -static constexpr OrtApi ort_api_1_to_21 = { +static constexpr OrtApi ort_api_1_to_22 = { // NOTE: The ordering of these fields MUST not change after that version has shipped since existing binaries depend on this ordering. // Shipped as version 1 - DO NOT MODIFY (see above text for more information) @@ -2812,6 +2775,19 @@ static constexpr OrtApi ort_api_1_to_21 = { &OrtApis::SetEpDynamicOptions, // End of Version 20 - DO NOT MODIFY ABOVE (see above text for more information) + + &OrtApis::ReleaseValueInfo, + &OrtApis::ReleaseNode, + &OrtApis::ReleaseGraph, + &OrtApis::ReleaseModel, + + &OrtApis::GetValueInfoName, + &OrtApis::GetValueInfoTypeInfo, + + &OrtApis::GetModelEditorApi, + + &OrtApis::CreateTensorWithDataAndDeleterAsOrtValue, + &OrtApis::SessionOptionsSetLoadCancellationFlag, }; // OrtApiBase can never change as there is no way to know what version of OrtApiBase is returned by OrtGetApiBase. @@ -2847,16 +2823,16 @@ static_assert(offsetof(OrtApi, AddExternalInitializersFromFilesInMemory) / sizeo static_assert(offsetof(OrtApi, SetEpDynamicOptions) / sizeof(void*) == 284, "Size of version 20 API cannot change"); // So that nobody forgets to finish an API version, this check will serve as a reminder: -static_assert(std::string_view(ORT_VERSION) == "1.21.0", +static_assert(std::string_view(ORT_VERSION) == "1.22.0", "ORT_Version change detected, please follow below steps to ensure OrtApi is updated properly"); // 1. Update the hardcoded version string in above static_assert to silence it -// 2. If there were any APIs added to ort_api_1_to_21 above: +// 2. If there were any APIs added to ort_api_1_to_22 above: // a. Add the 'End of version #' markers (pattern above should be obvious) // b. Add a static_assert in the directly above list of version sizes to ensure nobody adds any more functions to the just shipped API version ORT_API(const OrtApi*, OrtApis::GetApi, uint32_t version) { if (version >= 1 && version <= ORT_API_VERSION) - return &ort_api_1_to_21; + return &ort_api_1_to_22; fprintf(stderr, "The requested API version [%u] is not available, only API versions [1, %u] are supported in this build." diff --git a/onnxruntime/core/session/ort_apis.h b/onnxruntime/core/session/ort_apis.h index 52d3c98d526dc..0a87036a0dd1d 100644 --- a/onnxruntime/core/session/ort_apis.h +++ b/onnxruntime/core/session/ort_apis.h @@ -20,6 +20,10 @@ ORT_API(void, ReleaseCustomOpDomain, _Frees_ptr_opt_ OrtCustomOpDomain*); ORT_API(void, ReleaseMapTypeInfo, _Frees_ptr_opt_ OrtMapTypeInfo*); ORT_API(void, ReleaseSequenceTypeInfo, _Frees_ptr_opt_ OrtSequenceTypeInfo*); ORT_API(void, ReleaseModelMetadata, _Frees_ptr_opt_ OrtModelMetadata*); +ORT_API(void, ReleaseValueInfo, _Frees_ptr_opt_ OrtValueInfo*); +ORT_API(void, ReleaseNode, _Frees_ptr_opt_ OrtNode*); +ORT_API(void, ReleaseGraph, _Frees_ptr_opt_ OrtGraph*); +ORT_API(void, ReleaseModel, _Frees_ptr_opt_ OrtModel*); _Check_return_ _Ret_notnull_ [[nodiscard]] OrtStatus* ORT_API_CALL CreateStatus(OrtErrorCode code, _In_z_ const char* msg) NO_EXCEPTION; @@ -533,4 +537,19 @@ ORT_API_STATUS_IMPL(RunOptionsAddActiveLoraAdapter, _Inout_ OrtRunOptions* optio ORT_API_STATUS_IMPL(SetEpDynamicOptions, _Inout_ OrtSession* sess, _In_reads_(kv_len) const char* const* keys, _In_reads_(kv_len) const char* const* values, _In_ size_t kv_len); + +ORT_API_STATUS_IMPL(GetValueInfoName, _In_ const OrtValueInfo* value_info, _Out_ const char** name); +ORT_API_STATUS_IMPL(GetValueInfoTypeInfo, _In_ const OrtValueInfo* value_info, _Outptr_ const OrtTypeInfo** type_info); + +ORT_API(const OrtModelEditorApi*, GetModelEditorApi); + +ORT_API_STATUS_IMPL(CreateTensorWithDataAndDeleterAsOrtValue, _In_ OrtAllocator* deleter, + _In_ void* p_data, size_t p_data_len, + _In_ const int64_t* shape, size_t shape_len, + ONNXTensorElementDataType type, + _Outptr_ OrtValue** out); + +ORT_API_STATUS_IMPL(SessionOptionsSetLoadCancellationFlag, _Inout_ OrtSessionOptions* options, + _In_ bool is_cancel); + } // namespace OrtApis diff --git a/onnxruntime/core/session/provider_bridge_ort.cc b/onnxruntime/core/session/provider_bridge_ort.cc index 1c91418c24e93..c5e845d14fb30 100644 --- a/onnxruntime/core/session/provider_bridge_ort.cc +++ b/onnxruntime/core/session/provider_bridge_ort.cc @@ -4,6 +4,7 @@ // This is the Onnxruntime side of the bridge to allow providers to be built as a DLL // It implements onnxruntime::ProviderHost +#include #include "core/common/inlined_containers.h" #include "core/common/path_string.h" #include "core/framework/allocator_utils.h" @@ -35,12 +36,14 @@ #include "core/graph/graph_proto_serializer.h" #include "core/framework/murmurhash3.h" #include "core/framework/model_metadef_id_generator.h" +#include "core/optimizer/graph_optimizer_registry.h" #include "core/optimizer/qdq_transformer/selectors_actions/qdq_selectors.h" #include "core/optimizer/qdq_transformer/selectors_actions/shared/utils.h" #include "core/session/onnxruntime_c_api.h" #include "core/common/string_helper.h" #include +#include "onnx/shape_inference/implementation.h" #ifdef ENABLE_TRAINING #ifdef ENABLE_TRAINING_TORCH_INTEROP @@ -237,6 +240,21 @@ common::Status LoadDynamicLibraryFromProvider(onnxruntime::PathString library_na struct ProviderHostImpl : ProviderHost { const OrtApiBase* OrtGetApiBase() override { return ::OrtGetApiBase(); } + Status GetOptimizerByName(const std::string& name, + const GraphOptimizerRegistry& graph_optimizer_registry, + SelectionFunc& selection_func) override { + std::string optimizer_name(name); + + auto func = graph_optimizer_registry.GetSelectionFunc(optimizer_name); + + if (func.has_value()) { + selection_func = func.value(); + } else { + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Failed to get optimizer " + optimizer_name); + } + return Status::OK(); + }; + void* HeapAllocate(size_t size) override { return new uint8_t[size]; } void HeapFree(void* p) override { delete[] reinterpret_cast(p); } @@ -360,8 +378,9 @@ struct ProviderHostImpl : ProviderHost { std::vector> IExecutionProvider__GetCapability( const IExecutionProvider* p, const onnxruntime::GraphViewer& graph_viewer, const IExecutionProvider::IKernelLookup& kernel_lookup, + const GraphOptimizerRegistry& graph_optimizer_registry, IResourceAccountant* resource_accountant) override { - return p->IExecutionProvider::GetCapability(graph_viewer, kernel_lookup, resource_accountant); + return p->IExecutionProvider::GetCapability(graph_viewer, kernel_lookup, graph_optimizer_registry, resource_accountant); } common::Status IExecutionProvider__Compile(IExecutionProvider* p, const std::vector& fused_nodes_and_graphs, std::vector& node_compute_funcs) override { @@ -753,6 +772,12 @@ struct ProviderHostImpl : ProviderHost { int FunctionProto__metadata_props_size(const ONNX_NAMESPACE::FunctionProto* p) override { return p->metadata_props_size(); } ONNX_NAMESPACE::StringStringEntryProto* FunctionProto__add_metadata_props(ONNX_NAMESPACE::FunctionProto* p) override { return p->add_metadata_props(); } + void InferShapes(const std::string& m, const std::string& save_path) override { + return ONNX_NAMESPACE::shape_inference::InferShapes(m, save_path); + } + void InferShapes(ONNX_NAMESPACE::ModelProto& m) override { + return ONNX_NAMESPACE::shape_inference::InferShapes(m); + } void RegisterSchema(const std::string& domain, const OrtCustomOp* op) override { auto& domain_instance = ONNX_NAMESPACE::OpSchemaRegistry::DomainToVersionRange::Instance(); const auto& domain_to_version_map = domain_instance.Map(); @@ -797,6 +822,8 @@ struct ProviderHostImpl : ProviderHost { std::unique_ptr ComputeCapability__construct(std::unique_ptr t_sub_graph) override { return std::make_unique(std::move(t_sub_graph)); } void ComputeCapability__operator_delete(ComputeCapability* p) override { delete p; } std::unique_ptr& ComputeCapability__SubGraph(ComputeCapability* p) override { return p->sub_graph; } + void ComputeCapability__copy_optimization_func(ComputeCapability* p, ComputeCapability* selection_cc) override { p->optimization_func = selection_cc->optimization_func; } + void ComputeCapability__add_nodes_to_optimize(ComputeCapability* p, std::unique_ptr optimization_cc) override { p->nodes_to_optimize.push_back(std::move(optimization_cc)); } // DataTransferManager (wrapped) Status DataTransferManager__CopyTensor(const DataTransferManager* p, const Tensor& src, Tensor& dst) override { return p->CopyTensor(src, dst); } @@ -1248,6 +1275,7 @@ struct ProviderHostImpl : ProviderHost { const Graph* Graph__ParentGraph(const Graph* p) const override { return p->ParentGraph(); } Graph* Graph__MutableParentGraph(Graph* p) override { return p->MutableParentGraph(); } const std::string& Graph__Name(const Graph* p) const noexcept override { return p->Name(); } + void Graph__SetName(Graph* p, const std::string& name) const noexcept override { return p->SetName(name); } const std::filesystem::path& Graph__ModelPath(const Graph* p) const override { return p->ModelPath(); } const std::vector& Graph__GetInputsIncludingInitializers(const Graph* p) const noexcept override { return p->GetInputsIncludingInitializers(); } bool Graph__IsSubgraph(const Graph* p) override { return p->IsSubgraph(); } @@ -1616,7 +1644,7 @@ struct ProviderHostImpl : ProviderHost { } #endif - void MurmurHash3__x86_128(const void* key, int len, uint32_t seed, void* out) override { + void MurmurHash3__x86_128(const void* key, size_t len, uint32_t seed, void* out) override { MurmurHash3::x86_128(key, len, seed, out); } @@ -1631,6 +1659,7 @@ struct ProviderHostImpl : ProviderHost { Status LoadDynamicLibrary(onnxruntime::PathString library_name) override { return LoadDynamicLibraryFromProvider(library_name); }; #endif } provider_host_; + #if defined(_MSC_VER) && !defined(__clang__) #pragma warning(pop) #endif @@ -1923,6 +1952,7 @@ OrtTensorRTProviderOptionsV2 OrtTensorRTProviderOptionsToOrtTensorRTProviderOpti trt_options_converted.trt_ep_context_embed_mode = 0; trt_options_converted.trt_engine_cache_prefix = ""; trt_options_converted.trt_engine_hw_compatible = 0; + trt_options_converted.trt_preview_features = ""; return trt_options_converted; } @@ -2589,6 +2619,7 @@ ORT_API(void, OrtApis::ReleaseTensorRTProviderOptions, _Frees_ptr_opt_ OrtTensor delete[] ptr->trt_ep_context_file_path; delete[] ptr->trt_onnx_model_folder_path; delete[] ptr->trt_op_types_to_exclude; + delete[] ptr->trt_preview_features; } std::unique_ptr p(ptr); diff --git a/onnxruntime/core/session/utils.cc b/onnxruntime/core/session/utils.cc new file mode 100644 index 0000000000000..afb1ed2696c9f --- /dev/null +++ b/onnxruntime/core/session/utils.cc @@ -0,0 +1,125 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/session/utils.h" + +#include "core/framework/error_code_helper.h" +#include "core/framework/execution_provider.h" +#include "core/session/abi_session_options_impl.h" +// #include "core/session/environment.h" +#include "core/session/inference_session.h" +#include "core/session/inference_session_utils.h" +#include "core/session/onnxruntime_c_api.h" +#include "core/session/ort_apis.h" +#include "core/session/ort_env.h" + +using namespace onnxruntime; + +common::Status CopyStringToOutputArg(std::string_view str, const char* err_msg, char* out, size_t* size) { + const size_t str_len = str.size(); + const size_t req_size = str_len + 1; + + if (out == nullptr) { // User is querying the total output buffer size + *size = req_size; + return onnxruntime::common::Status::OK(); + } + + if (*size >= req_size) { // User provided a buffer of sufficient size + std::memcpy(out, str.data(), str_len); + out[str_len] = '\0'; + *size = req_size; + return onnxruntime::common::Status::OK(); + } + + // User has provided a buffer that is not large enough + *size = req_size; + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, err_msg); +} + +// provider either model_path, or modal_data + model_data_length. +OrtStatus* CreateSessionAndLoadModel(_In_ const OrtSessionOptions* options, + _In_ const OrtEnv* env, + _In_opt_z_ const ORTCHAR_T* model_path, + _In_opt_ const void* model_data, + size_t model_data_length, + std::unique_ptr& sess) { + // quick check here to decide load path. InferenceSession will provide error message for invalid values. + // TODO: Could move to a helper + const Env& os_env = Env::Default(); // OS environment (!= ORT environment) + bool load_config_from_model = + os_env.GetEnvironmentVar(inference_session_utils::kOrtLoadConfigFromModelEnvVar) == "1"; + + if (load_config_from_model) { +#if !defined(ORT_MINIMAL_BUILD) + if (model_path != nullptr) { + sess = std::make_unique( + options == nullptr ? onnxruntime::SessionOptions() : options->value, + env->GetEnvironment(), + model_path); + } else { + sess = std::make_unique( + options == nullptr ? onnxruntime::SessionOptions() : options->value, + env->GetEnvironment(), + model_data, static_cast(model_data_length)); + } +#else + return OrtApis::CreateStatus(ORT_FAIL, "Loading config from ONNX models is not supported in this build."); +#endif + } else { + sess = std::make_unique( + options == nullptr ? onnxruntime::SessionOptions() : options->value, + env->GetEnvironment()); + } + +#if !defined(ORT_MINIMAL_BUILD) || defined(ORT_MINIMAL_BUILD_CUSTOM_OPS) + // Add custom domains + if (options && !options->custom_op_domains_.empty()) { + ORT_API_RETURN_IF_STATUS_NOT_OK(sess->AddCustomOpDomains(options->custom_op_domains_)); + } +#endif + + // Finish load + if (load_config_from_model) { +#if !defined(ORT_MINIMAL_BUILD) + ORT_API_RETURN_IF_STATUS_NOT_OK(sess->Load()); +#endif + } else { + if (model_path != nullptr) { + ORT_API_RETURN_IF_STATUS_NOT_OK(sess->Load(model_path)); + } else { + ORT_API_RETURN_IF_STATUS_NOT_OK(sess->Load(model_data, static_cast(model_data_length))); + } + } + + return nullptr; +} + +OrtStatus* InitializeSession(_In_ const OrtSessionOptions* options, + _In_ onnxruntime::InferenceSession& sess, + _Inout_opt_ OrtPrepackedWeightsContainer* prepacked_weights_container) { + // we need to disable mem pattern if DML is one of the providers since DML doesn't have the concept of + // byte addressable memory + std::vector> provider_list; + if (options) { + for (auto& factory : options->provider_factories) { + auto provider = factory->CreateProvider(); + provider_list.push_back(std::move(provider)); + } + } + + // register the providers + for (auto& provider : provider_list) { + if (provider) { + ORT_API_RETURN_IF_STATUS_NOT_OK(sess.RegisterExecutionProvider(std::move(provider))); + } + } + + if (prepacked_weights_container != nullptr) { + ORT_API_RETURN_IF_STATUS_NOT_OK(sess.AddPrePackedWeightsContainer( + reinterpret_cast(prepacked_weights_container))); + } + + ORT_API_RETURN_IF_STATUS_NOT_OK(sess.Initialize()); + + return nullptr; +} diff --git a/onnxruntime/core/session/utils.h b/onnxruntime/core/session/utils.h new file mode 100644 index 0000000000000..ac8ad60758b5b --- /dev/null +++ b/onnxruntime/core/session/utils.h @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include "core/common/common.h" +#include "core/session/onnxruntime_c_api.h" + +onnxruntime::common::Status CopyStringToOutputArg(std::string_view str, const char* err_msg, char* out, size_t* size); + +struct OrtSessionOptions; +struct OrtStatus; +struct OrtPrepackedWeightsContainer; +namespace onnxruntime { +class InferenceSession; +} + +OrtStatus* CreateSessionAndLoadModel(_In_ const OrtSessionOptions* options, + _In_ const OrtEnv* env, + _In_opt_z_ const ORTCHAR_T* model_path, + _In_opt_ const void* model_data, + size_t model_data_length, + std::unique_ptr& sess); + +OrtStatus* InitializeSession(_In_ const OrtSessionOptions* options, + _In_ onnxruntime::InferenceSession& sess, + _Inout_opt_ OrtPrepackedWeightsContainer* prepacked_weights_container = nullptr); diff --git a/onnxruntime/python/onnxruntime_inference_collection.py b/onnxruntime/python/onnxruntime_inference_collection.py index 6b5f7526cc506..785eb9c485d25 100644 --- a/onnxruntime/python/onnxruntime_inference_collection.py +++ b/onnxruntime/python/onnxruntime_inference_collection.py @@ -15,6 +15,9 @@ from onnxruntime.capi import _pybind_state as C if typing.TYPE_CHECKING: + import numpy as np + import numpy.typing as npt + import onnxruntime @@ -59,22 +62,22 @@ def export_adapter(self, file_path: os.PathLike): """ self._adapter.export_adapter(file_path) - def get_format_version(self): + def get_format_version(self) -> int: return self._adapter.format_version - def set_adapter_version(self, adapter_version: int): + def set_adapter_version(self, adapter_version: int) -> None: self._adapter.adapter_version = adapter_version - def get_adapter_version(self): + def get_adapter_version(self) -> int: return self._adapter.adapter_version - def set_model_version(self, model_version: int): + def set_model_version(self, model_version: int) -> None: self._adapter.model_version = model_version - def get_model_version(self): + def get_model_version(self) -> int: return self._adapter.model_version - def set_parameters(self, params: dict[str, OrtValue]): + def set_parameters(self, params: dict[str, OrtValue]) -> None: self._adapter.parameters = {k: v._ortvalue for k, v in params.items()} def get_parameters(self) -> dict[str, OrtValue]: @@ -174,27 +177,27 @@ def __init__(self): self._sess = None self._enable_fallback = True - def get_session_options(self): + def get_session_options(self) -> onnxruntime.SessionOptions: "Return the session options. See :class:`onnxruntime.SessionOptions`." return self._sess_options - def get_inputs(self): + def get_inputs(self) -> Sequence[onnxruntime.NodeArg]: "Return the inputs metadata as a list of :class:`onnxruntime.NodeArg`." return self._inputs_meta - def get_outputs(self): + def get_outputs(self) -> Sequence[onnxruntime.NodeArg]: "Return the outputs metadata as a list of :class:`onnxruntime.NodeArg`." return self._outputs_meta - def get_overridable_initializers(self): + def get_overridable_initializers(self) -> Sequence[onnxruntime.NodeArg]: "Return the inputs (including initializers) metadata as a list of :class:`onnxruntime.NodeArg`." return self._overridable_initializers - def get_modelmeta(self): + def get_modelmeta(self) -> onnxruntime.ModelMetadata: "Return the metadata. See :class:`onnxruntime.ModelMetadata`." return self._model_meta - def get_providers(self): + def get_providers(self) -> Sequence[str]: "Return list of registered execution providers." return self._providers @@ -202,7 +205,7 @@ def get_provider_options(self): "Return registered execution providers' configurations." return self._provider_options - def set_providers(self, providers=None, provider_options=None): + def set_providers(self, providers=None, provider_options=None) -> None: """ Register the input list of execution providers. The underlying session is re-created. @@ -224,13 +227,13 @@ def set_providers(self, providers=None, provider_options=None): # recreate the underlying C.InferenceSession self._reset_session(providers, provider_options) - def disable_fallback(self): + def disable_fallback(self) -> None: """ Disable session.run() fallback mechanism. """ self._enable_fallback = False - def enable_fallback(self): + def enable_fallback(self) -> None: """ Enable session.Run() fallback mechanism. If session.Run() fails due to an internal Execution Provider failure, reset the Execution Providers enabled for this session. @@ -249,7 +252,7 @@ def _validate_input(self, feed_input_names): f"Required inputs ({missing_input_names}) are missing from input feed ({feed_input_names})." ) - def run(self, output_names, input_feed, run_options=None): + def run(self, output_names, input_feed, run_options=None) -> Sequence[np.ndarray | SparseTensor | list | dict]: """ Compute the predictions. @@ -308,7 +311,7 @@ def callback(results: np.ndarray, user_data: MyData, err: str) -> None: output_names = [output.name for output in self._outputs_meta] return self._sess.run_async(output_names, input_feed, callback, user_data, run_options) - def run_with_ort_values(self, output_names, input_dict_ort_values, run_options=None): + def run_with_ort_values(self, output_names, input_dict_ort_values, run_options=None) -> Sequence[OrtValue]: """ Compute the predictions. @@ -367,7 +370,7 @@ def get_profiling_start_time_ns(self): """ return self._sess.get_profiling_start_time_ns - def io_binding(self): + def io_binding(self) -> IOBinding: "Return an onnxruntime.IOBinding object`." return IOBinding(self) @@ -550,7 +553,7 @@ def _create_inference_session(self, providers, provider_options, disabled_optimi self._provider_options = self._sess.get_provider_options() self._profiling_start_time_ns = self._sess.get_profiling_start_time_ns - def _reset_session(self, providers, provider_options): + def _reset_session(self, providers, provider_options) -> None: "release underlying session object." # meta data references session internal structures # so they must be set to None to decrement _sess reference count. @@ -721,7 +724,7 @@ class OrtValue: This class provides APIs to construct and deal with OrtValues. """ - def __init__(self, ortvalue, numpy_obj=None): + def __init__(self, ortvalue: C.OrtValue, numpy_obj: np.ndarray | None = None): if isinstance(ortvalue, C.OrtValue): self._ortvalue = ortvalue # Hold a ref count to the numpy object if the OrtValue is backed directly @@ -733,11 +736,11 @@ def __init__(self, ortvalue, numpy_obj=None): "`Provided ortvalue` needs to be of type `onnxruntime.capi.onnxruntime_pybind11_state.OrtValue`" ) - def _get_c_value(self): + def _get_c_value(self) -> C.OrtValue: return self._ortvalue - @staticmethod - def ortvalue_from_numpy(numpy_obj, device_type="cpu", device_id=0): + @classmethod + def ortvalue_from_numpy(cls, numpy_obj: np.ndarray, /, device_type="cpu", device_id=0) -> OrtValue: """ Factory method to construct an OrtValue (which holds a Tensor) from a given Numpy object A copy of the data in the Numpy object is held by the OrtValue only if the device is NOT cpu @@ -749,7 +752,7 @@ def ortvalue_from_numpy(numpy_obj, device_type="cpu", device_id=0): # Hold a reference to the numpy object (if device_type is 'cpu') as the OrtValue # is backed directly by the data buffer of the numpy object and so the numpy object # must be around until this OrtValue instance is around - return OrtValue( + return cls( C.OrtValue.ortvalue_from_numpy( numpy_obj, C.OrtDevice( @@ -761,8 +764,8 @@ def ortvalue_from_numpy(numpy_obj, device_type="cpu", device_id=0): numpy_obj if device_type.lower() == "cpu" else None, ) - @staticmethod - def ortvalue_from_numpy_with_onnx_type(data, onnx_element_type: int): + @classmethod + def ortvalue_from_numpy_with_onnx_type(cls, data: np.ndarray, /, onnx_element_type: int) -> OrtValue: """ This method creates an instance of OrtValue on top of the numpy array. No data copy is made and the lifespan of the resulting OrtValue should never @@ -771,12 +774,14 @@ def ortvalue_from_numpy_with_onnx_type(data, onnx_element_type: int): when we want to use an ONNX data type that is not supported by numpy. :param data: numpy.ndarray. - :param onnx_elemenet_type: a valid onnx TensorProto::DataType enum value + :param onnx_element_type: a valid onnx TensorProto::DataType enum value """ - return OrtValue(C.OrtValue.ortvalue_from_numpy_with_onnx_type(data, onnx_element_type), data) + return cls(C.OrtValue.ortvalue_from_numpy_with_onnx_type(data, onnx_element_type), data) - @staticmethod - def ortvalue_from_shape_and_type(shape, element_type, device_type: str = "cpu", device_id: int = 0): + @classmethod + def ortvalue_from_shape_and_type( + cls, shape: Sequence[int], element_type, device_type: str = "cpu", device_id: int = 0 + ) -> OrtValue: """ Factory method to construct an OrtValue (which holds a Tensor) from given shape and element_type @@ -788,7 +793,7 @@ def ortvalue_from_shape_and_type(shape, element_type, device_type: str = "cpu", # Integer for onnx element type (see https://onnx.ai/onnx/api/mapping.html). # This is helpful for some data type (like TensorProto.BFLOAT16) that is not available in numpy. if isinstance(element_type, int): - return OrtValue( + return cls( C.OrtValue.ortvalue_from_shape_and_onnx_type( shape, element_type, @@ -800,7 +805,7 @@ def ortvalue_from_shape_and_type(shape, element_type, device_type: str = "cpu", ) ) - return OrtValue( + return cls( C.OrtValue.ortvalue_from_shape_and_type( shape, element_type, @@ -812,77 +817,77 @@ def ortvalue_from_shape_and_type(shape, element_type, device_type: str = "cpu", ) ) - @staticmethod - def ort_value_from_sparse_tensor(sparse_tensor): + @classmethod + def ort_value_from_sparse_tensor(cls, sparse_tensor: SparseTensor) -> OrtValue: """ The function will construct an OrtValue instance from a valid SparseTensor The new instance of OrtValue will assume the ownership of sparse_tensor """ - return OrtValue(C.OrtValue.ort_value_from_sparse_tensor(sparse_tensor._get_c_tensor())) + return cls(C.OrtValue.ort_value_from_sparse_tensor(sparse_tensor._get_c_tensor())) - def as_sparse_tensor(self): + def as_sparse_tensor(self) -> SparseTensor: """ The function will return SparseTensor contained in this OrtValue """ return SparseTensor(self._ortvalue.as_sparse_tensor()) - def data_ptr(self): + def data_ptr(self) -> int: """ Returns the address of the first element in the OrtValue's data buffer """ return self._ortvalue.data_ptr() - def device_name(self): + def device_name(self) -> str: """ Returns the name of the device where the OrtValue's data buffer resides e.g. cpu, cuda, cann """ return self._ortvalue.device_name().lower() - def shape(self): + def shape(self) -> Sequence[int]: """ Returns the shape of the data in the OrtValue """ return self._ortvalue.shape() - def data_type(self): + def data_type(self) -> str: """ - Returns the data type of the data in the OrtValue + Returns the data type of the data in the OrtValue. E.g. 'tensor(int64)' """ return self._ortvalue.data_type() - def element_type(self): + def element_type(self) -> int: """ Returns the proto type of the data in the OrtValue if the OrtValue is a tensor. """ return self._ortvalue.element_type() - def has_value(self): + def has_value(self) -> bool: """ Returns True if the OrtValue corresponding to an optional type contains data, else returns False """ return self._ortvalue.has_value() - def is_tensor(self): + def is_tensor(self) -> bool: """ Returns True if the OrtValue contains a Tensor, else returns False """ return self._ortvalue.is_tensor() - def is_sparse_tensor(self): + def is_sparse_tensor(self) -> bool: """ Returns True if the OrtValue contains a SparseTensor, else returns False """ return self._ortvalue.is_sparse_tensor() - def is_tensor_sequence(self): + def is_tensor_sequence(self) -> bool: """ Returns True if the OrtValue contains a Tensor Sequence, else returns False """ return self._ortvalue.is_tensor_sequence() - def numpy(self): + def numpy(self) -> np.ndarray: """ Returns a Numpy object from the OrtValue. Valid only for OrtValues holding Tensors. Throws for OrtValues holding non-Tensors. @@ -890,7 +895,7 @@ def numpy(self): """ return self._ortvalue.numpy() - def update_inplace(self, np_arr): + def update_inplace(self, np_arr) -> None: """ Update the OrtValue in place with a new Numpy array. The numpy contents are copied over to the device memory backing the OrtValue. It can be used @@ -948,7 +953,7 @@ class SparseTensor: depending on the format """ - def __init__(self, sparse_tensor): + def __init__(self, sparse_tensor: C.SparseTensor): """ Internal constructor """ @@ -960,11 +965,17 @@ def __init__(self, sparse_tensor): "`Provided object` needs to be of type `onnxruntime.capi.onnxruntime_pybind11_state.SparseTensor`" ) - def _get_c_tensor(self): + def _get_c_tensor(self) -> C.SparseTensor: return self._tensor - @staticmethod - def sparse_coo_from_numpy(dense_shape, values, coo_indices, ort_device): + @classmethod + def sparse_coo_from_numpy( + cls, + dense_shape: npt.NDArray[np.int64], + values: np.ndarray, + coo_indices: npt.NDArray[np.int64], + ort_device: OrtDevice, + ) -> SparseTensor: """ Factory method to construct a SparseTensor in COO format from given arguments @@ -985,12 +996,17 @@ def sparse_coo_from_numpy(dense_shape, values, coo_indices, ort_device): For strings and objects, it will create a copy of the arrays in CPU memory as ORT does not support those on other devices and their memory can not be mapped. """ - return SparseTensor( - C.SparseTensor.sparse_coo_from_numpy(dense_shape, values, coo_indices, ort_device._get_c_device()) - ) + return cls(C.SparseTensor.sparse_coo_from_numpy(dense_shape, values, coo_indices, ort_device._get_c_device())) - @staticmethod - def sparse_csr_from_numpy(dense_shape, values, inner_indices, outer_indices, ort_device): + @classmethod + def sparse_csr_from_numpy( + cls, + dense_shape: npt.NDArray[np.int64], + values: np.ndarray, + inner_indices: npt.NDArray[np.int64], + outer_indices: npt.NDArray[np.int64], + ort_device: OrtDevice, + ) -> SparseTensor: """ Factory method to construct a SparseTensor in CSR format from given arguments @@ -1011,7 +1027,7 @@ def sparse_csr_from_numpy(dense_shape, values, inner_indices, outer_indices, ort For strings and objects, it will create a copy of the arrays in CPU memory as ORT does not support those on other devices and their memory can not be mapped. """ - return SparseTensor( + return cls( C.SparseTensor.sparse_csr_from_numpy( dense_shape, values, @@ -1021,7 +1037,7 @@ def sparse_csr_from_numpy(dense_shape, values, inner_indices, outer_indices, ort ) ) - def values(self): + def values(self) -> np.ndarray: """ The method returns a numpy array that is backed by the native memory if the data type is numeric. Otherwise, the returned numpy array that contains @@ -1093,19 +1109,19 @@ def format(self): """ return self._tensor.format - def dense_shape(self): + def dense_shape(self) -> npt.NDArray[np.int64]: """ Returns a numpy array(int64) containing a dense shape of a sparse tensor """ return self._tensor.dense_shape() - def data_type(self): + def data_type(self) -> str: """ Returns a string data type of the data in the OrtValue """ return self._tensor.data_type() - def device_name(self): + def device_name(self) -> str: """ Returns the name of the device where the SparseTensor data buffers reside e.g. cpu, cuda """ diff --git a/onnxruntime/python/onnxruntime_pybind_state.cc b/onnxruntime/python/onnxruntime_pybind_state.cc index de4d93c4afd05..22914c9dec7fe 100644 --- a/onnxruntime/python/onnxruntime_pybind_state.cc +++ b/onnxruntime/python/onnxruntime_pybind_state.cc @@ -526,7 +526,7 @@ std::unique_ptr CreateExecutionProviderInstance( // and TRT EP instance, so it won't be released.) std::string calibration_table, cache_path, cache_prefix, timing_cache_path, lib_path, trt_tactic_sources, trt_extra_plugin_lib_paths, min_profile, max_profile, opt_profile, ep_context_file_path, - onnx_model_folder_path, trt_op_types_to_exclude; + onnx_model_folder_path, trt_op_types_to_exclude, preview_features; auto it = provider_options_map.find(type); if (it != provider_options_map.end()) { OrtTensorRTProviderOptionsV2 params; @@ -827,6 +827,11 @@ std::unique_ptr CreateExecutionProviderInstance( } else if (option.first == "trt_op_types_to_exclude") { trt_op_types_to_exclude = option.second; params.trt_op_types_to_exclude = trt_op_types_to_exclude.c_str(); + } else if (option.first == "trt_preview_features") { + if (!option.second.empty()) { + preview_features = option.second; + params.trt_preview_features = preview_features.c_str(); + } } else { ORT_THROW("Invalid TensorRT EP option: ", option.first); } @@ -1751,6 +1756,12 @@ Applies to session load, initialization, etc. Default is 0.)pbdoc") options->value.execution_mode = execution_mode; }, R"pbdoc(Sets the execution mode. Default is sequential.)pbdoc") + .def( + "set_load_cancellation_flag", + [](PySessionOptions* options, bool value) -> void { + options->value.SetLoadCancellationFlag(value); + }, + R"pbdoc(Request inference session load cancellation)pbdoc") .def_property( "execution_order", [](const PySessionOptions* options) -> ExecutionOrder { return options->value.execution_order; }, diff --git a/onnxruntime/python/tools/pytorch_export_contrib_ops.py b/onnxruntime/python/tools/pytorch_export_contrib_ops.py index f3cd4c2c89801..bdfd2ce332217 100644 --- a/onnxruntime/python/tools/pytorch_export_contrib_ops.py +++ b/onnxruntime/python/tools/pytorch_export_contrib_ops.py @@ -22,8 +22,8 @@ _registered_ops: typing.AbstractSet[str] = set() -def _reg(symbolic_fn: typing.Callable): - name = f"::{symbolic_fn.__name__}" +def _reg(symbolic_fn: typing.Callable, namespace: str = ""): + name = f"{namespace}::{symbolic_fn.__name__}" torch.onnx.register_custom_op_symbolic(name, symbolic_fn, _OPSET_VERSION) _registered_ops.add(name) @@ -91,6 +91,26 @@ def tril(g, self, diagonal): _reg(tril) + @torch.onnx.symbolic_helper.parse_args("v") + def DynamicTimeWarping(g, self): # noqa: N802 + return g.op("com.microsoft::DynamicTimeWarping", self) + + _reg(DynamicTimeWarping, namespace="onnxruntime") + + def UnfoldTensor(g, self, dim, size, step): # noqa: N802 + dim = int(symbolic_helper._maybe_get_const(dim, "i")) + size = int(symbolic_helper._maybe_get_const(size, "i")) + step = int(symbolic_helper._maybe_get_const(step, "i")) + return g.op( + "com.microsoft::UnfoldTensor", + self, + dim_i=dim, + size_i=size, + step_i=step, + ).setType(self.type().with_sizes([None, None, None, None, size])) + + _reg(UnfoldTensor, namespace="onnxruntime") + def unregister(): """Unregister ONNX Runtime's built-in contrib ops.""" diff --git a/onnxruntime/python/tools/symbolic_shape_infer.py b/onnxruntime/python/tools/symbolic_shape_infer.py index fda604d3f729b..33f5b5e5853a5 100755 --- a/onnxruntime/python/tools/symbolic_shape_infer.py +++ b/onnxruntime/python/tools/symbolic_shape_infer.py @@ -126,6 +126,7 @@ class SymbolicShapeInference: def __init__(self, int_max, auto_merge, guess_output_rank, verbose, prefix=""): self.dispatcher_ = { "Add": self._infer_symbolic_compute_ops, + "AllReduce": self._pass_on_shape_and_type, "ArrayFeatureExtractor": self._infer_ArrayFeatureExtractor, "AveragePool": self._infer_Pool, "BatchNormalization": self._infer_BatchNormalization, @@ -147,7 +148,6 @@ def __init__(self, int_max, auto_merge, guess_output_rank, verbose, prefix=""): "GatherElements": self._infer_GatherElements, "GatherND": self._infer_GatherND, "Identity": self._pass_on_shape_and_type, - "AllReduce": self._pass_on_shape_and_type, "If": self._infer_If, "Loop": self._infer_Loop, "MatMul": self._infer_MatMul, @@ -199,6 +199,7 @@ def __init__(self, int_max, auto_merge, guess_output_rank, verbose, prefix=""): "BiasSplitGelu": self._infer_BiasSplitGelu, "DecoderMaskedMultiHeadAttention": self._infer_DecoderMaskedMultiHeadAttention, "DequantizeLinear": self._infer_DequantizeLinear, + "DynamicTimeWarping": self._infer_DynamicTimeWarping, "EmbedLayerNormalization": self._infer_EmbedLayerNormalization, "FastGelu": self._infer_FastGelu, "GatedRelativePositionBias": self._infer_GatedRelativePositionBias, @@ -218,6 +219,8 @@ def __init__(self, int_max, auto_merge, guess_output_rank, verbose, prefix=""): "PackedMultiHeadAttention": self._infer_PackedMultiHeadAttention, "PagedAttention": self._infer_PagedAttention, "PythonOp": self._infer_PythonOp, + "QLinearAdd": self._infer_QLinearBinary, + "QLinearMul": self._infer_QLinearBinary, "QuantizeLinear": self._infer_QuantizeLinear, "QuickGelu": self._infer_FastGelu, "RelativePositionBias": self._infer_RelativePositionBias, @@ -229,6 +232,7 @@ def __init__(self, int_max, auto_merge, guess_output_rank, verbose, prefix=""): "SkipLayerNormalization": self._infer_SkipLayerNormalization, "SkipSimplifiedLayerNormalization": self._infer_SkipLayerNormalization, "SparseAttention": self._infer_SparseAttention, + "UnfoldTensor": self._infer_UnfoldTensor, } self.aten_op_dispatcher_ = { "embedding": self._infer_Gather, @@ -457,36 +461,39 @@ def _onnx_infer_single_node(self, node): "SplitToSequence", "ZipMap", # contrib ops "Attention", + "BiasAdd", "BiasGelu", + "BiasSplitGelu", + "DequantizeLinear", + "DynamicTimeWarping", "EmbedLayerNormalization", "FastGelu", "GatherBlockQuantized", "Gelu", "GemmFastGelu", + "GroupNorm", + "GroupNormalization", + "GroupQueryAttention", "LayerNormalization", "LongformerAttention", - "DequantizeLinear", + "MultiHeadAttention", + "NhwcConv", + "PackedAttention", + "PagedAttention", + "PythonOp", "QuantizeLinear", + "QuickGelu", "RelativePositionBias", "RemovePadding", "RestorePadding", + "RotaryEmbedding", "SimplifiedLayerNormalization", "SkipLayerNormalization", "SkipSimplifiedLayerNormalization", - "PackedAttention", - "PagedAttention", - "PythonOp", - "MultiHeadAttention", - "GroupNorm", - "GroupNormalization", - "GroupQueryAttention", "SparseAttention", "SkipGroupNorm", - "BiasSplitGelu", - "BiasAdd", - "NhwcConv", - "QuickGelu", - "RotaryEmbedding", + "QLinearAdd", + "QLinearMul", ] if not skip_infer: @@ -1037,6 +1044,20 @@ def _infer_QuantizeLinear(self, node): # noqa: N802 vi = self.known_vi_[node.output[0]] vi.CopyFrom(helper.make_tensor_value_info(node.output[0], output_dtype, output_shape)) + def _infer_QLinearBinary(self, node): # noqa: N802 + # Get the output data type from the first input to QLinearAdd / QLinearMul. + output_dtype = self.known_vi_[node.input[0]].type.tensor_type.elem_type + + # The inputs are first and fourth operands respectively. + input_1_shape = self._get_shape(node, 0) + input_2_shape = self._get_shape(node, 3) + + # Compute the broadcasted shape + new_shape = self._broadcast_shapes(input_1_shape, input_2_shape) + + vi = self.known_vi_[node.output[0]] + vi.CopyFrom(helper.make_tensor_value_info(node.output[0], output_dtype, new_shape)) + def _infer_Einsum(self, node): # noqa: N802 # ref:https://github.com/onnx/onnx/blob/623dfaa0151b2e4ce49779c3ec31cbd78c592b80/onnx/defs/math/defs.cc#L3275 equation = get_attribute(node, "equation") @@ -2413,6 +2434,42 @@ def _infer_DecoderMaskedMultiHeadAttention(self, node): # noqa: N802 vi = self.known_vi_[node.output[2]] vi.CopyFrom(helper.make_tensor_value_info(vi.name, output_dtype, past_shape)) + def _infer_UnfoldTensor(self, node): # noqa: N802 + input_shape = self._get_shape(node, 0) + if input_shape is not None: + output_shape = input_shape.copy() + output_dtype = self.known_vi_[node.input[0]].type.tensor_type.elem_type + assert output_dtype is not None + + rank, dim, size, step = len(input_shape), None, None, None + for attr in node.attribute: + if attr.name == "dim": + dim = attr.i + dim = rank + dim if dim == -1 else dim + elif attr.name == "size": + size = attr.i + elif attr.name == "step": + step = attr.i + + output_shape.append(size) + output_shape[dim] = (input_shape[dim] - size) // step + 1 + + vi = self.known_vi_[node.output[0]] + vi.CopyFrom(helper.make_tensor_value_info(node.output[0], output_dtype, output_shape)) + + def _infer_DynamicTimeWarping(self, node): # noqa: N802 + # Input 0 has shape M x N or 1 x M x N + # Output 0 has shape (2, O) where max(M, N) <= O < M + N + input_shape = self._get_shape(node, 0) + if input_shape is not None: + shape_len = len(input_shape) + assert shape_len == 2 or shape_len == 3 + M, N = input_shape[shape_len - 2], input_shape[shape_len - 1] # noqa: N806 + output_shape = [2, f"max({M}, {N}) <= O < {M} + {N}"] + output_dtype = onnx.TensorProto.FLOAT + vi = self.known_vi_[node.output[0]] + vi.CopyFrom(helper.make_tensor_value_info(node.output[0], output_dtype, output_shape)) + def _infer_FastGelu(self, node): # noqa: N802 self._propagate_shape_and_type(node) diff --git a/onnxruntime/python/tools/tensorrt/perf/build/build_image.py b/onnxruntime/python/tools/tensorrt/perf/build/build_image.py index 7af34447f1f66..a4fbc21b43c85 100644 --- a/onnxruntime/python/tools/tensorrt/perf/build/build_image.py +++ b/onnxruntime/python/tools/tensorrt/perf/build/build_image.py @@ -16,8 +16,7 @@ import sys TRT_DOCKER_FILES = { - "10.8_cuda11.8_cudnn8": "tools/ci_build/github/linux/docker/Dockerfile.ubuntu_cuda11_tensorrt10", - "10.8_cuda12.6_cudnn9": "tools/ci_build/github/linux/docker/Dockerfile.ubuntu_cuda12_tensorrt10", + "10.9_cuda12.8_cudnn9": "tools/ci_build/github/linux/docker/Dockerfile.ubuntu_cuda12_tensorrt10", "BIN": "tools/ci_build/github/linux/docker/Dockerfile.ubuntu_tensorrt_bin", } diff --git a/onnxruntime/python/tools/transformers/benchmark_helper.py b/onnxruntime/python/tools/transformers/benchmark_helper.py index 2a210729112d7..3dd2c2ef945ec 100644 --- a/onnxruntime/python/tools/transformers/benchmark_helper.py +++ b/onnxruntime/python/tools/transformers/benchmark_helper.py @@ -88,61 +88,62 @@ def create_onnxruntime_session( enable_mlas_gemm_fastmath_arm64_bfloat16=False, provider_options={}, # map execution provider name to its option # noqa: B006 ): - session = None - try: - sess_options = onnxruntime.SessionOptions() + sess_options = onnxruntime.SessionOptions() - if enable_all_optimization: - sess_options.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_ENABLE_ALL - else: - sess_options.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_ENABLE_BASIC + if enable_all_optimization: + sess_options.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_ENABLE_ALL + else: + sess_options.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_ENABLE_BASIC - if enable_profiling: - sess_options.enable_profiling = True + if enable_profiling: + sess_options.enable_profiling = True - if num_threads > 0: - sess_options.intra_op_num_threads = num_threads - logger.debug(f"Session option: intra_op_num_threads={sess_options.intra_op_num_threads}") + if num_threads > 0: + sess_options.intra_op_num_threads = num_threads + logger.debug(f"Session option: intra_op_num_threads={sess_options.intra_op_num_threads}") - if verbose: - sess_options.log_severity_level = 0 - else: - sess_options.log_severity_level = 4 - - logger.debug(f"Create session for onnx model: {onnx_model_path}") - if use_gpu: - if provider == "dml": - providers = ["DmlExecutionProvider", "CPUExecutionProvider"] - elif provider == "rocm": - providers = ["ROCMExecutionProvider", "CPUExecutionProvider"] - elif provider == "migraphx": - providers = [ - "MIGraphXExecutionProvider", - "ROCMExecutionProvider", - "CPUExecutionProvider", - ] - elif provider == "cuda": - providers = ["CUDAExecutionProvider", "CPUExecutionProvider"] - elif provider == "tensorrt": - providers = [ - "TensorrtExecutionProvider", - "CUDAExecutionProvider", - "CPUExecutionProvider", - ] - else: - providers = ["CUDAExecutionProvider", "CPUExecutionProvider"] + if verbose: + sess_options.log_severity_level = 0 + else: + sess_options.log_severity_level = 4 + + if provider in onnxruntime.get_available_providers(): + providers = [provider] + elif use_gpu: + if provider == "dml": + providers = ["DmlExecutionProvider", "CPUExecutionProvider"] + elif provider == "rocm": + providers = ["ROCMExecutionProvider", "CPUExecutionProvider"] + elif provider == "migraphx": + providers = [ + "MIGraphXExecutionProvider", + "ROCMExecutionProvider", + "CPUExecutionProvider", + ] + elif provider == "cuda" or provider is None: + providers = ["CUDAExecutionProvider", "CPUExecutionProvider"] + elif provider == "tensorrt": + providers = [ + "TensorrtExecutionProvider", + "CUDAExecutionProvider", + "CPUExecutionProvider", + ] else: - providers = ["CPUExecutionProvider"] + raise RuntimeError(f"The execution provider is not supported: {provider}") + else: + providers = ["CPUExecutionProvider"] - if provider_options: - providers = [(name, provider_options[name]) if name in provider_options else name for name in providers] + if provider_options: + providers = [(name, provider_options[name]) if name in provider_options else name for name in providers] - if enable_mlas_gemm_fastmath_arm64_bfloat16: - sess_options.add_session_config_entry("mlas.enable_gemm_fastmath_arm64_bfloat16", "1") + if enable_mlas_gemm_fastmath_arm64_bfloat16: + sess_options.add_session_config_entry("mlas.enable_gemm_fastmath_arm64_bfloat16", "1") + session = None + try: session = onnxruntime.InferenceSession(onnx_model_path, sess_options, providers=providers) except Exception: - logger.error("Exception", exc_info=True) # noqa: G201 + logger.exception(f"Failed to create session for {onnx_model_path} with providers={providers}") return session diff --git a/onnxruntime/python/tools/transformers/convert_generation.py b/onnxruntime/python/tools/transformers/convert_generation.py index 68bf9e9e69059..8eb2afb3db896 100644 --- a/onnxruntime/python/tools/transformers/convert_generation.py +++ b/onnxruntime/python/tools/transformers/convert_generation.py @@ -16,19 +16,17 @@ python convert_generation.py -m gpt2 --output gpt2_beam_search.onnx --use_gpu -p fp16 --use_sln_strict_mode Example 4: convert T5 model with beam search in two steps: - cd ./models/t5 - python convert_to_onnx.py -m t5-small - cd ../.. - python convert_generation.py -m t5-small --model_type t5 \ - --decoder_onnx ./models/t5/onnx_models/t5-small_decoder.onnx \ - --encoder_decoder_init_onnx ./models/t5/onnx_models/t5-small_encoder_decoder_init.onnx \ - --output ./models/t5/onnx_models/t5_small_beam_search.onnx + python -m models.t5.convert_to_onnx -m t5-small + python convert_generation.py -m t5-small --model_type t5 \ + --decoder_onnx ./onnx_models/t5-small_decoder.onnx \ + --encoder_decoder_init_onnx ./onnx_models/t5-small_encoder.onnx \ + --output ./onnx_models/t5_small_beam_search.onnx Example 5: convert T5 model with beam search. All in one step: - python convert_generation.py -m t5-small --model_type t5 --output ./models/t5/onnx_models/t5_small_beam_search.onnx + python convert_generation.py -m t5-small --model_type t5 --output t5_small_beam_search.onnx Example 6: convert T5 model with beam search containing specific cuda optimizations. All in one step: - python convert_generation.py -m t5-small --model_type t5 --output ./models/t5/onnx_models/t5_small_beam_search.onnx \ + python convert_generation.py -m t5-small --model_type t5 --output t5_small_beam_search.onnx \ --use_gpu --past_present_share_buffer --use_decoder_masked_attention Example 7: convert MT5 model with external data file like mt5-base-beamsearch.onnx.data in below example. @@ -68,11 +66,23 @@ T5Tokenizer, ) -from onnxruntime import GraphOptimizationLevel, InferenceSession, SessionOptions, get_available_providers -from onnxruntime.transformers.models.gpt2.convert_to_onnx import main as convert_gpt2_to_onnx +from onnxruntime import ( + GraphOptimizationLevel, + InferenceSession, + SessionOptions, + get_available_providers, +) +from onnxruntime.transformers.models.gpt2.convert_to_onnx import ( + main as convert_gpt2_to_onnx, +) from onnxruntime.transformers.models.gpt2.gpt2_helper import PRETRAINED_GPT2_MODELS -from onnxruntime.transformers.models.t5.convert_to_onnx import export_onnx_models as export_t5_onnx_models -from onnxruntime.transformers.models.t5.t5_helper import PRETRAINED_MT5_MODELS, PRETRAINED_T5_MODELS +from onnxruntime.transformers.models.t5.convert_to_onnx import ( + export_onnx_models as export_t5_onnx_models, +) +from onnxruntime.transformers.models.t5.t5_helper import ( + PRETRAINED_MT5_MODELS, + PRETRAINED_T5_MODELS, +) logger = logging.getLogger("") @@ -162,9 +172,9 @@ def parse_arguments(argv: list[str] | None = None) -> argparse.Namespace: "-p", "--precision", required=False, - type=Precision, - default=Precision.FLOAT32, - choices=[Precision.FLOAT32, Precision.FLOAT16], + type=str, + default=Precision.FLOAT32.value, + choices=[Precision.FLOAT32.value, Precision.FLOAT16.value], help="Precision of model to run. fp32 for full precision, fp16 for half or mixed precision", ) @@ -189,7 +199,11 @@ def parse_arguments(argv: list[str] | None = None) -> argparse.Namespace: output_group.set_defaults(use_external_data_format=False) output_group.add_argument( - "-s", "--run_shape_inference", required=False, action="store_true", help="run shape inference" + "-s", + "--run_shape_inference", + required=False, + action="store_true", + help="run shape inference", ) output_group.set_defaults(run_shape_inference=False) @@ -223,6 +237,14 @@ def parse_arguments(argv: list[str] | None = None) -> argparse.Namespace: ) output_group.set_defaults(disable_shared_initializers=False) + output_group.add_argument( + "--encoder_decoder_init", + required=False, + action="store_true", + help="Add decoder initialization to encoder for T5 model. This is legacy format that will be deprecated.", + ) + output_group.set_defaults(encoder_decoder_init=False) + model_group = parser.add_argument_group("Beam search parameters that stored in the output model") model_group.add_argument( @@ -426,7 +448,10 @@ def parse_arguments(argv: list[str] | None = None) -> argparse.Namespace: test_group.set_defaults(use_sln_strict_mode=False) test_group.add_argument( - "--use_gpu", required=False, action="store_true", help="use GPU for inference. Required for fp16." + "--use_gpu", + required=False, + action="store_true", + help="use GPU for inference. Required for fp16.", ) test_group.set_defaults(use_gpu=False) @@ -490,7 +515,7 @@ def gpt2_to_onnx(args: argparse.Namespace): args.decoder_onnx, "--optimize_onnx", "--precision", - "fp32" if args.precision == Precision.FLOAT32 else "fp16", + args.precision, "--test_runs", "1", "--test_cases", @@ -508,7 +533,7 @@ def gpt2_to_onnx(args: argparse.Namespace): arguments.extend(["--op_block_list"]) arguments.extend(args.op_block_list) - if args.precision == Precision.FLOAT16: + if args.precision == Precision.FLOAT16.value: assert args.use_gpu, "fp16 or mixed precision model cannot run in CPU. Please add --use_gpu" # TODO(tianleiwu): Use auto mixed precision for fp16 conversion: arguments.append('--auto_mixed_precision') # Need change cuda kernel to support a combination of fp32 logits and fp16 past state. @@ -527,20 +552,21 @@ def t5_to_onnx(args: argparse.Namespace): args (argparse.Namespace): arguments parsed from command line """ paths = export_t5_onnx_models( - args.model_name_or_path, - args.cache_dir, - Path(args.output).parent, + model_name_or_path=args.model_name_or_path, + cache_dir=args.cache_dir, + output_dir=Path(args.output).parent, use_gpu=args.use_gpu, use_external_data_format=args.use_external_data_format, - optimize_onnx=(args.precision != Precision.FLOAT16), + optimize_onnx=(args.precision != Precision.FLOAT16.value), precision=args.precision, verbose=False, use_decoder_start_token=False, - merge_encoder_and_decoder_init=True, overwrite=True, disable_auto_mixed_precision=False, use_int32_inputs=True, model_type=args.model_type, + encoder_decoder_init=args.encoder_decoder_init, + force_fp16_io=(args.precision == Precision.FLOAT16.value), # required by BeamSearch op implementation. ) logger.debug(f"onnx model for encoder: {paths[0]}") @@ -693,7 +719,7 @@ def verify_gpt2_subgraph(graph: onnx.GraphProto, precision: Precision): ValueError: Output name is not expected. ValueError: Output data type is not expected. """ - is_float16 = precision == Precision.FLOAT16 + is_float16 = precision == Precision.FLOAT16.value input_count = len(graph.input) layer_count = input_count - 3 @@ -749,7 +775,7 @@ def verify_t5_decoder_subgraph(graph: onnx.GraphProto, precision: Precision): ValueError: Output name is not expected. ValueError: Output data type is not expected. """ - is_float16 = precision == Precision.FLOAT16 + is_float16 = precision == Precision.FLOAT16.value float_type = TensorProto.FLOAT16 if is_float16 else TensorProto.FLOAT input_count = len(graph.input) @@ -825,15 +851,20 @@ def verify_t5_encoder_decoder_init_subgraph(graph: onnx.GraphProto, precision: P ValueError: Output name is not expected. ValueError: Output data type is not expected. """ - is_float16 = precision == Precision.FLOAT16 - layer_count = (len(graph.output) - 2) // 4 - assert layer_count >= 1 + is_float16 = precision == Precision.FLOAT16.value + new_format = "cross" in graph.output[0].name # Expect 3 inputs: # encoder_input_ids: int32 (B, encode_sequence_length) # encoder_attention_mask: int32 (B, encode_sequence_length) # decoder_input_ids: int32 (B, 1) - expected_inputs = ["encoder_input_ids", "encoder_attention_mask", "decoder_input_ids"] + expected_inputs = [ + "encoder_input_ids", + "encoder_attention_mask", + "decoder_input_ids", + ] + if new_format: + expected_inputs = expected_inputs[:2] if len(graph.input) != len(expected_inputs): raise ValueError(f"Number of inputs expected to be {len(expected_inputs)}. Got {len(graph.input)}") @@ -846,22 +877,41 @@ def verify_t5_encoder_decoder_init_subgraph(graph: onnx.GraphProto, precision: P if input_type != expected_type: raise ValueError(f"Input {i} is expected to have onnx data type {expected_type}. Got {input_type}") - # Expected outputs: - # logits: (B, 1, vocab_size) - # encoder_hidden_states: (B, encode_sequence_length, encoder_hidden_size) - # present_key_self_0: (B, num_heads, 1, head_size) - # present_value_self_0: (B, num_heads, 1, head_size) - # ... (for each self attention layer) - # present_key_cross_0: (B, num_heads, encode_sequence_length, head_size) - # present_value_cross_0: (B, num_heads, encode_sequence_length, head_size) - # ... (for each cross attention layer) - expected_outputs = ["logits", "encoder_hidden_states"] - for i in range(layer_count): - expected_outputs.append(f"present_key_self_{i}") - expected_outputs.append(f"present_value_self_{i}") - for i in range(layer_count): - expected_outputs.append(f"present_key_cross_{i}") - expected_outputs.append(f"present_value_cross_{i}") + if new_format: + assert len(graph.output) % 2 == 0 + layer_count = len(graph.output) // 2 + assert layer_count >= 1 + + # Expected outputs: + # present_key_cross_0: (B, num_heads, encode_sequence_length, head_size) + # present_value_cross_0: (B, num_heads, encode_sequence_length, head_size) + # ... (for each cross attention layer) + expected_outputs = [] + for i in range(layer_count): + expected_outputs.append(f"present_key_cross_{i}") + expected_outputs.append(f"present_value_cross_{i}") + else: + logger.warning("This format is deprecated. Please export T5 encoder in new format with only cross outputs.") + assert (len(graph.output) - 2) % 4 == 0 + layer_count = (len(graph.output) - 2) // 4 + assert layer_count >= 1 + + # Expected outputs: + # logits: (B, 1, vocab_size) + # encoder_hidden_states: (B, encode_sequence_length, encoder_hidden_size) + # present_key_self_0: (B, num_heads, 1, head_size) + # present_value_self_0: (B, num_heads, 1, head_size) + # ... (for each self attention layer) + # present_key_cross_0: (B, num_heads, encode_sequence_length, head_size) + # present_value_cross_0: (B, num_heads, encode_sequence_length, head_size) + # ... (for each cross attention layer) + expected_outputs = ["logits", "encoder_hidden_states"] + for i in range(layer_count): + expected_outputs.append(f"present_key_self_{i}") + expected_outputs.append(f"present_value_self_{i}") + for i in range(layer_count): + expected_outputs.append(f"present_key_cross_{i}") + expected_outputs.append(f"present_value_cross_{i}") if len(graph.output) != len(expected_outputs): raise ValueError(f"Number of outputs expected to be {len(expected_outputs)}. Got {len(graph.output)}") @@ -1116,6 +1166,7 @@ def update_decoder_subgraph_past_present_share_buffer(subg: GraphProto): new_nodes = [] for node in subg.node: + new_node = node if node.op_type == "Attention": kwargs = kwargs_of(node) kwargs.update({"past_present_share_buffer": 1}) @@ -1125,8 +1176,8 @@ def update_decoder_subgraph_past_present_share_buffer(subg: GraphProto): nis.extend([""]) if len(nis) < 7: nis.extend(["past_sequence_length"]) - node = onnx.helper.make_node("Attention", nis, node.output, name=node.name, **kwargs) # noqa: PLW2901 - new_nodes.extend([node]) + new_node = onnx.helper.make_node("Attention", nis, node.output, name=node.name, **kwargs) + new_nodes.extend([new_node]) subg.ClearField("node") subg.node.extend(new_nodes) return subg @@ -1152,7 +1203,9 @@ def update_decoder_subgraph_use_decoder_masked_attention( new_inputs.extend( [ onnx.helper.make_tensor_value_info( - "cache_indirection", onnx.TensorProto.INT32, shape=["batch_size", "beam_width", "max_seq_len"] + "cache_indirection", + onnx.TensorProto.INT32, + shape=["batch_size", "beam_width", "max_seq_len"], ) ] ) @@ -1203,7 +1256,11 @@ def update_decoder_subgraph_use_decoder_masked_attention( nis.extend(["cache_indirection"]) node = onnx.helper.make_node( # noqa: PLW2901 - "DecoderMaskedSelfAttention", nis, node.output, name=node.name, **kwargs + "DecoderMaskedSelfAttention", + nis, + node.output, + name=node.name, + **kwargs, ) new_nodes.extend([node]) subg.ClearField("node") @@ -1241,39 +1298,343 @@ def find_past_seq_len_usage(subg: GraphProto): output_name_to_node[output_name] = node for node in subg.node: - # find "Shape(past_key_self..) --> Gather(*, 2)" + # find "past_key_self_0 --> [Transpose(past_key_self_0) --> Reshape(past_key_self_0)] --> Shape(past_key_self_0) --> Gather(*, 2)" + # where [Transpose(past_key_self_0) --> Reshape(past_key_self_0)] may or may not exist if node.op_type == "Gather": if not node.input[1] or not node.input[0]: continue + + # Find Gather node's index value shape_tensor_name, shape_index_name = (node.input[0], node.input[1]) ini_gather_indices = None - for tensor in subg.initializer: - if tensor.name == shape_index_name: - ini_gather_indices = tensor - break + if "Constant_" in shape_index_name: + # If shape_index_name refers to a Constant node + for const_node in subg.node: + if const_node.op_type == "Constant" and const_node.output[0] == shape_index_name: + ini_gather_indices = const_node.attribute[0].t + break + else: + # If shape_index_name refers to an initializer + for tensor in subg.initializer: + if tensor.name == shape_index_name: + ini_gather_indices = tensor + break if ini_gather_indices is None: continue gather_indices_arr = onnx.numpy_helper.to_array(ini_gather_indices) - if gather_indices_arr.size == 1 and gather_indices_arr.item() == 2 and node.input[0] in output_name_to_node: + + if ( + gather_indices_arr.size == 1 + and gather_indices_arr.item() in {1, 2} + and node.input[0] in output_name_to_node + ): shape_node = output_name_to_node[shape_tensor_name] + if not (shape_node.op_type == "Shape" and shape_node.input[0]): + continue + if ( - shape_node.op_type == "Shape" - and shape_node.input[0] - and shape_node.input[0] in graph_input_names + shape_node.input[0] in graph_input_names and ( shape_node.input[0].startswith("past_key_self_") or shape_node.input[0].startswith("past_value_self_") ) + and gather_indices_arr.item() == 2 ): + # "past_key_self_0 --> Shape(past_key_self_0) --> Gather(*, 2)" tensor_names_to_rename.add(node.output[0]) nodes_to_remove.append(node) if len(input_name_to_nodes[shape_node.output[0]]) == 1: nodes_to_remove.append(shape_node) + continue + + if shape_node.input[0] not in output_name_to_node: + continue + reshape_node = output_name_to_node[shape_node.input[0]] + if not (reshape_node.op_type == "Reshape" and reshape_node.input[0]): + continue + transpose_node = output_name_to_node[reshape_node.input[0]] + if not (transpose_node.op_type == "Transpose" and transpose_node.input[0]): + continue + + if ( + transpose_node.input[0] in graph_input_names + and ( + transpose_node.input[0].startswith("past_key_self_") + or transpose_node.input[0].startswith("past_value_self_") + ) + and gather_indices_arr.item() == 1 + ): + # "past_key_self_0 --> Transpose(past_key_self_0) --> Reshape(past_key_self_0) --> Shape(past_key_self_0) --> Gather(*, 2)" + tensor_names_to_rename.add(node.output[0]) + nodes_to_remove.extend([node, shape_node, reshape_node]) + if len(input_name_to_nodes[transpose_node.output[0]]) == 1: + nodes_to_remove.append(transpose_node) + continue + return tensor_names_to_rename, nodes_to_remove +def add_cache_indirection_to_mha(model: OnnxModel, past_seq_len_name: str): + # Add past_sequence_length and cache_indirection as inputs to all MultiHeadAttention ops and as inputs to model + cache_indirection_name = "cache_indirection" + mha_nodes = list(filter(lambda node: node.op_type == "MultiHeadAttention", model.model.graph.node)) + for node in mha_nodes: + # MHA op takes the following potential inputs: + # query, key, value, bias, key_padding_mask, add_qk, past_key, past_value + while len(node.input) < 8: + node.input.append("") + node.input.append(past_seq_len_name) + node.input.append(cache_indirection_name) + + model.model.graph.input.append( + onnx.helper.make_tensor_value_info( + cache_indirection_name, TensorProto.INT32, shape=["batch_size", "beam_width", "max_sequence_length"] + ), + ) + model.topological_sort() + return model + + +def add_output_qk_to_mha(model: OnnxModel, dtype: int = 0, skip_node_idxs: list[int] = []): # noqa: B006 + # Add output_qk as output to MultiHeadAttention ops and as outputs to model + output_qk_basename = "output_cross_qk" + output_qks = [] + mha_nodes = list(filter(lambda node: node.op_type == "MultiHeadAttention", model.model.graph.node)) + for idx, node in enumerate(mha_nodes): + # Skip MHA nodes where output_qk does not need to be added + if idx in skip_node_idxs: + continue + + # Get `num_heads` attribute from MHA + num_heads = 0 + for att in node.attribute: + if att.name == "num_heads": + num_heads = att.i + break + + # Get dtype for `output_qk` based on MHA bias if not provided + output_qk_dtype = dtype + if output_qk_dtype == 0: + for i in model.model.graph.initializer: + if i.name == node.input[3]: + output_qk_dtype = i.data_type + break + + # Get `target_sequence_length` attribute from 4D input for key if it's a constant + target_sequence_length = "target_sequence_length" + for i in model.model.graph.input: + if i.name == node.input[1]: + target_sequence_length = i.type.tensor_type.shape.dim[2].dim_value + break + + # MHA op takes the following potential outputs: + # output, present_key, present_value + while len(node.output) < 3: + node.output.append("") + + output_qk_name = f"{output_qk_basename}_{idx // 2}" + node.output.append(output_qk_name) + output_qks.append( + onnx.helper.make_tensor_value_info( + output_qk_name, + output_qk_dtype, + shape=["batch_size", num_heads, "sequence_length", target_sequence_length], + ), + ) + + model.model.graph.output.extend(output_qks) + model.topological_sort() + return model + + +def fix_past_sequence_length(model: ModelProto): + # Modify total_sequence_length = past_sequence_length + curr_sequence_length subgraph to calculate + # past_sequence_length from the new `past_sequence_length` input of size 1D and type int32 instead of + # from `past_key_self_0` since DecoderMaskedMultiHeadAttention (DMMHA) uses buffer sharing and + # `past_key_self_0.shape[2] = max_sequence_length` instead of `past_key_self_0.shape[2] = past_sequence_length` + # when buffer sharing is enabled + # + # Before: + # + # input_ids past_key_self_0 + # | | + # Shape Shape + # | | + # Gather Gather + # (idx=1) (idx=2) + # | | \ + # +--------+--------+ Unsqueeze + # | + # Add + # + # After: + # + # input_ids past_sequence_length (1D) + # | | + # Shape Squeeze + # | | + # Gather Cast + # (idx=1) (int64) + # | | \ + # +--------+--------+ Unsqueeze + # | + # Add + + node = list(filter(lambda n: n.op_type == "LayerNormalization", model.model.graph.node))[0] # noqa: RUF015 + + base_path = model.match_parent_path( + node, + ["Add", "Slice"], + [0, 1], + ) + if base_path is None: + return + + left_path = model.match_parent_path( + base_path[-1], + ["Unsqueeze", "Add", "Gather", "Shape"], + [2, 0, 0, 0], + ) + right_path = model.match_parent_path( + base_path[-1], + ["Unsqueeze", "Gather", "Shape"], + [1, 0, 0], + ) + long_right_path = model.match_parent_path( + base_path[-1], + ["Unsqueeze", "Gather", "Shape", "Reshape", "Transpose"], + [1, 0, 0, 0, 0], + ) + if left_path is None or right_path is None or left_path[-2:] != right_path[-2:]: + return + + # Remove `past_key_self_0 --> [Transpose --> Reshape] --> Shape --> Gather` connection + # where `Transpose --> Reshape` part may or may not exist. The OpenAI implementation of + # Whisper has an extra `Transpose --> Reshape` connection to remove. + constant_node = list(filter(lambda n: n.output[0] == left_path[-2].input[1], model.model.graph.node))[0] # noqa: RUF015 + model.model.graph.node.remove(left_path[-2]) + model.model.graph.node.remove(left_path[-1]) + model.model.graph.node.remove(constant_node) + if long_right_path is not None: + # Remove `Transpose --> Reshape` part + model.model.graph.node.remove(long_right_path[-2]) + model.model.graph.node.remove(long_right_path[-1]) + + # Add `past_sequence_length` as model input + past_seq_len_name = "past_sequence_length" + model.model.graph.input.append( + onnx.helper.make_tensor_value_info(past_seq_len_name, TensorProto.INT32, shape=[1]), + ) + + # Add `past_sequence_length --> Squeeze --> Cast` connection + past_seq_len_int32 = "past_seq_len_int32" + past_seq_len_int64 = "past_seq_len_int64" + + squeeze_node = onnx.helper.make_node( + "Squeeze", + inputs=[past_seq_len_name], + outputs=[past_seq_len_int32], + name=model.create_node_name("Squeeze"), + ) + squeeze_output = onnx.helper.make_tensor_value_info(past_seq_len_int32, TensorProto.INT32, shape=[]) + cast_node = onnx.helper.make_node( + "Cast", + inputs=[past_seq_len_int32], + outputs=[past_seq_len_int64], + name=model.create_node_name("Cast"), + to=TensorProto.INT64, + ) + cast_output = onnx.helper.make_tensor_value_info(past_seq_len_int64, TensorProto.INT64, shape=[]) + + model.model.graph.value_info.extend([squeeze_output, cast_output]) + + # Add `past_seq_len_int64` as an input name to existing nodes + left_path[1].input[0] = past_seq_len_int64 + right_path[0].input[0] = past_seq_len_int64 + + # Add new nodes to graph + model.model.graph.node.extend([squeeze_node, cast_node]) + model.topological_sort() + return model, past_seq_len_name + + +def replace_mha_with_dmmha(model: OnnxModel, past_seq_len_name: str): + # Add `beam_width` and `cache_indirection` as model inputs + beam_width = "beam_width" + cache_indirection = "cache_indirection" + + model.model.graph.input.extend( + [ + onnx.helper.make_tensor_value_info(beam_width, TensorProto.INT32, shape=[1]), + onnx.helper.make_tensor_value_info( + cache_indirection, TensorProto.INT32, shape=["batch_size", "beam_width", "max_sequence_length"] + ), + ] + ) + + # Replace all `MultiHeadAttention` nodes with `DecoderMaskedMultiHeadAttention` nodes + mha_nodes = list(filter(lambda node: node.op_type == "MultiHeadAttention", model.model.graph.node)) + for idx, node in enumerate(mha_nodes): + # Get `num_heads` attribute from MHA + num_heads = 0 + for att in node.attribute: + if att.name == "num_heads": + num_heads = att.i + break + + # Make Q*K outputs for cross-attention layers, which happen every alternative layer + qk_output_name = f"output_cross_qk_{idx // 2}" + qk_output = onnx.helper.make_tensor_value_info( + qk_output_name, TensorProto.FLOAT, shape=["batch_size", num_heads, 1, "encode_sequence_length / 2"] + ) + if idx % 2 == 1: + model.model.graph.output.append(qk_output) + + # Make DMMHA node + dmmha_node = onnx.helper.make_node( + "DecoderMaskedMultiHeadAttention", + inputs=[ + node.input[0], # query + node.input[1], # key + node.input[2], # value + "", # mask_index + "", # relative_position_bias + node.input[6] if len(node.input) > 4 else "", # past_key + node.input[7] if len(node.input) > 4 else "", # past_value + past_seq_len_name, # past_sequence_length + beam_width, # beam_width + cache_indirection, # cache_indirection + node.input[3], # bias + ], + outputs=[ + node.output[0], # output + node.output[1] if len(node.input) > 4 else "", # present_key + node.output[2] if len(node.input) > 4 else "", # present_value + qk_output_name if idx % 2 == 1 else "", # output_cross_qk + ], + name=node.name.replace("MultiHeadAttention", "DecoderMaskedMultiHeadAttention"), + domain="com.microsoft", + num_heads=num_heads, + output_qk=(idx % 2), + past_present_share_buffer=1, + ) + if idx % 2 == 0: + # Remove empty string for output_cross_qk, which happens every alternative layer + dmmha_node.output.remove("") + + model.model.graph.node.remove(node) + model.model.graph.node.extend([dmmha_node]) + + model.topological_sort() + return model + + def replace_mha_with_gqa( - model: OnnxModel, attn_mask: str, kv_num_heads: int = 0, world_size: int = 1, window_size: int = -1 + model: OnnxModel, + attn_mask: str, + kv_num_heads: int = 0, + world_size: int = 1, + window_size: int = -1, ): # Insert attention_mask subgraph to calculate shared inputs for all GroupQueryAttention nodes # @@ -1335,7 +1696,14 @@ def replace_mha_with_gqa( to=TensorProto.INT32, ) model.model.graph.node.extend( - [reduce_sum_node, sub_node, seqlen_k_cast_node, shape_node, gather_node, total_seqlen_cast_node] + [ + reduce_sum_node, + sub_node, + seqlen_k_cast_node, + shape_node, + gather_node, + total_seqlen_cast_node, + ] ) # Replace MultiHeadAttention with GroupQueryAttention @@ -1476,14 +1844,14 @@ def replace_mha_with_gqa( node.input[7], # past_value seqlen_k_cast_node.output[0], # seqlens_k (for attention mask) total_seqlen_cast_node.output[0], # total_seq_len (for attention mask) - q_rotary.input[2] if q_rotary is not None else "", # cos_cache (for rotary embeddings) - q_rotary.input[3] if q_rotary is not None else "", # sin_cache (for rotary embeddings) + (q_rotary.input[2] if q_rotary is not None else ""), # cos_cache (for rotary embeddings) + (q_rotary.input[3] if q_rotary is not None else ""), # sin_cache (for rotary embeddings) ], outputs=node.output, name=node.name.replace("MultiHeadAttention", "GroupQueryAttention"), domain="com.microsoft", num_heads=num_heads // world_size, - kv_num_heads=num_heads // world_size if kv_num_heads == 0 else kv_num_heads // world_size, + kv_num_heads=(num_heads // world_size if kv_num_heads == 0 else kv_num_heads // world_size), local_window_size=window_size, do_rotary=int(q_rotary is not None and k_rotary is not None), rotary_interleaved=interleaved, @@ -1510,7 +1878,7 @@ def update_decoder_subgraph_output_cross_attention(subg: GraphProto): num_layers = (len(subg.output) - output_self_present_0) // 2 input_cross_past_0 = 2 * num_layers + input_self_past_0 past_key_cross_inputs = {subg.input[layer * 2 + input_cross_past_0].name: layer for layer in range(num_layers)} - print(f" --past_key_cross_inputs={past_key_cross_inputs}") + print(f" -- past_key_cross_inputs = {past_key_cross_inputs}") input_past_key_cross_0_shape = shape_of(subg.input[input_cross_past_0]) print(f"past_key_cross_0_shape is {input_past_key_cross_0_shape}") @@ -1531,7 +1899,9 @@ def update_decoder_subgraph_output_cross_attention(subg: GraphProto): node.attribute.extend([onnx.helper.make_attribute("output_qk", 1)]) cross_attention = onnx.helper.make_tensor_value_info( - cross_attention_out_name, TensorProto.FLOAT, [batch_size_dim, num_heads_dim, 1, cross_seq_len_dim] + cross_attention_out_name, + TensorProto.FLOAT, + [batch_size_dim, num_heads_dim, 1, cross_seq_len_dim], ) subg.output.extend([cross_attention]) if num_layer_output_qk != num_layers: @@ -1579,9 +1949,9 @@ def update_decoder_subgraph_share_buffer_and_use_decoder_masked_mha(subg: ModelP tensor_names_to_rename, nodes_to_remove = find_past_seq_len_usage(subg) if len(tensor_names_to_rename) > 0: for name_to_rename in tensor_names_to_rename: - print(f"Found tensor name {name_to_rename} to be renamed to {target_squeezed_past_seq_name}") + print(f"Found tensor name `{name_to_rename}` to be renamed to `{target_squeezed_past_seq_name}`") for nr in nodes_to_remove: - print(f"Found node to removed: type:{nr.op_type}, name:{nr.name}") + print(f"Found node to remove: type = {nr.op_type}, name = {nr.name}") squeeze_node = onnx.helper.make_node( "Squeeze", @@ -1635,7 +2005,11 @@ def update_decoder_subgraph_share_buffer_and_use_decoder_masked_mha(subg: ModelP kwargs["past_present_share_buffer"] = 1 node = onnx.helper.make_node( # noqa: PLW2901 - "DecoderMaskedMultiHeadAttention", nis, node.output, name=node.name, **kwargs + "DecoderMaskedMultiHeadAttention", + nis, + node.output, + name=node.name, + **kwargs, ) if node not in nodes_to_remove: @@ -1668,7 +2042,9 @@ def update_decoder_subgraph_share_buffer_and_use_decoder_masked_mha(subg: ModelP new_inputs.extend( [ onnx.helper.make_tensor_value_info( - "cache_indirection", onnx.TensorProto.INT32, shape=["batch_size", "beam_width", "max_seq_len"] + "cache_indirection", + onnx.TensorProto.INT32, + shape=["batch_size", "beam_width", "max_seq_len"], ) ] ) @@ -1720,7 +2096,7 @@ def pack_qkv_for_decoder_masked_mha(model_proto: ModelProto): matmul_node_name = onnx_model.create_node_name("MatMul", name_prefix="MatMul_QKV") weight = onnx.helper.make_tensor( name=matmul_node_name + "_weight", - data_type=TensorProto.FLOAT if q_weight.data_type == 1 else TensorProto.FLOAT16, + data_type=(TensorProto.FLOAT if q_weight.data_type == 1 else TensorProto.FLOAT16), dims=[qkv_weight.shape[0], qkv_weight.shape[1]], vals=qkv_weight.flatten().tolist(), ) @@ -1774,12 +2150,18 @@ def update_input_shapes_for_gpt2_decoder_model(decoder_onnx_path: str, use_exter # Update dim_value to be 1 shape_dim_proto.dim_value = 1 - OnnxModel.save(decoder_model_proto, decoder_onnx_path, save_as_external_data=use_external_data_format) + OnnxModel.save( + decoder_model_proto, + decoder_onnx_path, + save_as_external_data=use_external_data_format, + ) return True def generate_gpt2_init_decoder( - decoder_onnx_path: str, init_decoder_onnx_path: str, use_external_data_format: bool = True + decoder_onnx_path: str, + init_decoder_onnx_path: str, + use_external_data_format: bool = True, ) -> bool: """Generates the initial decoder GPT2 subgraph and saves it for downstream use. The initial decoder model will be saved to init_decoder_onnx_path. @@ -1852,7 +2234,16 @@ def generate_gpt2_init_decoder( # Normalization Node is : LayerNormalization logits_matmul_to_residual_add_path = gpt2_init_decoder_model.match_parent_path( logits_matmul_node, - ["LayerNormalization", "Add", "Add", "MatMul", "FastGelu", "MatMul", "LayerNormalization", "Add"], + [ + "LayerNormalization", + "Add", + "Add", + "MatMul", + "FastGelu", + "MatMul", + "LayerNormalization", + "Add", + ], [0, 0, 1, 0, 0, 0, 0, 0], ) @@ -1883,7 +2274,9 @@ def generate_gpt2_init_decoder( if not is_skiplayernorm_path: residual_add_to_attention_parent_index = 0 residual_add_to_attention_path = gpt2_init_decoder_model.match_parent_path( - residual_add_node, ["Add", "Cast", "MatMul", "Attention"], [residual_add_to_attention_parent_index, 0, 0, 0] + residual_add_node, + ["Add", "Cast", "MatMul", "Attention"], + [residual_add_to_attention_parent_index, 0, 0, 0], ) # Try other parent index of the residual Add node @@ -1899,42 +2292,54 @@ def generate_gpt2_init_decoder( if residual_add_to_attention_path is None: residual_add_to_attention_parent_index = 0 residual_add_to_attention_path = gpt2_init_decoder_model.match_parent_path( - residual_add_node, ["Add", "MatMul", "Attention"], [residual_add_to_attention_parent_index, 0, 0] + residual_add_node, + ["Add", "MatMul", "Attention"], + [residual_add_to_attention_parent_index, 0, 0], ) # Try without the Casts before and after the MatMuls and other parent index of the residual Add node if residual_add_to_attention_path is None: residual_add_to_attention_parent_index = 1 residual_add_to_attention_path = gpt2_init_decoder_model.match_parent_path( - residual_add_node, ["Add", "MatMul", "Attention"], [residual_add_to_attention_parent_index, 0, 0] + residual_add_node, + ["Add", "MatMul", "Attention"], + [residual_add_to_attention_parent_index, 0, 0], ) # SkipLayerNormalization path else: residual_add_to_attention_parent_index = 0 residual_add_to_attention_path = gpt2_init_decoder_model.match_parent_path( - residual_add_node, ["Cast", "MatMul", "Attention"], [residual_add_to_attention_parent_index, 0, 0] + residual_add_node, + ["Cast", "MatMul", "Attention"], + [residual_add_to_attention_parent_index, 0, 0], ) # Try other parent index of the residual Add node if residual_add_to_attention_path is None: residual_add_to_attention_parent_index = 1 residual_add_to_attention_path = gpt2_init_decoder_model.match_parent_path( - residual_add_node, ["Cast", "MatMul", "Attention"], [residual_add_to_attention_parent_index, 0, 0] + residual_add_node, + ["Cast", "MatMul", "Attention"], + [residual_add_to_attention_parent_index, 0, 0], ) # Try without the Casts before and after the MatMuls if residual_add_to_attention_path is None: residual_add_to_attention_parent_index = 0 residual_add_to_attention_path = gpt2_init_decoder_model.match_parent_path( - residual_add_node, ["MatMul", "Attention"], [residual_add_to_attention_parent_index, 0] + residual_add_node, + ["MatMul", "Attention"], + [residual_add_to_attention_parent_index, 0], ) # Try without the Casts before and after the MatMuls and other parent index of the residual Add node if residual_add_to_attention_path is None: residual_add_to_attention_parent_index = 1 residual_add_to_attention_path = gpt2_init_decoder_model.match_parent_path( - residual_add_node, ["MatMul", "Attention"], [residual_add_to_attention_parent_index, 0] + residual_add_node, + ["MatMul", "Attention"], + [residual_add_to_attention_parent_index, 0], ) # TODO(hasesh): Are there more permutations to try before returning ? @@ -1952,7 +2357,9 @@ def generate_gpt2_init_decoder( # SkipLayerNormalization path else: add_before_residual_add = gpt2_init_decoder_model.match_parent( - residual_add_node, "SkipLayerNormalization", residual_add_to_add_parent_index + residual_add_node, + "SkipLayerNormalization", + residual_add_to_add_parent_index, ) if add_before_residual_add is None: @@ -2042,7 +2449,11 @@ def generate_gpt2_init_decoder( gpt2_init_decoder_model.topological_sort() # Save the init decoder model - OnnxModel.save(init_decoder_model_proto, init_decoder_onnx_path, save_as_external_data=use_external_data_format) + OnnxModel.save( + init_decoder_model_proto, + init_decoder_onnx_path, + save_as_external_data=use_external_data_format, + ) return True @@ -2083,7 +2494,10 @@ def make_dim_proto_numeric_t5(model, config): dim_proto.dim_value = dim_value -def convert_generation_model(args: argparse.Namespace, generation_type: GenerationType = GenerationType.BEAMSEARCH): +def convert_generation_model( + args: argparse.Namespace, + generation_type: GenerationType = GenerationType.BEAMSEARCH, +): """Convert model according to command line arguments. Args: @@ -2097,8 +2511,13 @@ def convert_generation_model(args: argparse.Namespace, generation_type: Generati logger.info(f"**** past_present_share_buffer={past_present_share_buffer}") if len(args.op_block_list) == 1 and args.op_block_list[0] == "auto": - if is_gpt2 and args.precision == Precision.FLOAT16: - args.op_block_list = ["Add", "LayerNormalization", "SkipLayerNormalization", "FastGelu"] + if is_gpt2 and args.precision == Precision.FLOAT16.value: + args.op_block_list = [ + "Add", + "LayerNormalization", + "SkipLayerNormalization", + "FastGelu", + ] logger.info(f"**** Setting op_block_list to {args.op_block_list}") logger.info("**** use --op_block_list if you want to override the block operator list.") else: @@ -2134,9 +2553,7 @@ def convert_generation_model(args: argparse.Namespace, generation_type: Generati logger.info(f"skip convert_to_onnx since path existed: {args.decoder_onnx}") else: if not args.decoder_onnx: - onnx_filename = "{}_past_{}.onnx".format( - args.model_name_or_path, "fp16" if args.precision == Precision.FLOAT16 else "fp32" - ) + onnx_filename = f"{args.model_name_or_path}_past_{args.precision}.onnx" args.decoder_onnx = Path(Path(args.output).parent, onnx_filename).as_posix() logger.info(f"Convert GPT model {args.model_name_or_path} to onnx {args.decoder_onnx} ...") @@ -2158,7 +2575,7 @@ def convert_generation_model(args: argparse.Namespace, generation_type: Generati logits_matmul_weight_padded = False if ( not args.disable_pad_vocab_size - and args.precision == Precision.FLOAT16 + and args.precision == Precision.FLOAT16.value and is_gpt2 and (is_beamsearch or is_greedysearch or is_sampling) ): @@ -2181,14 +2598,14 @@ def convert_generation_model(args: argparse.Namespace, generation_type: Generati ): logger.info(f"Creating an initial run GPT2 decoder from {args.decoder_onnx}. ") - gpt2_init_decoder_onnx_filename = "gpt2_init_past_{}.onnx".format( - "fp16" if args.precision == Precision.FLOAT16 else "fp32" - ) + gpt2_init_decoder_onnx_filename = f"gpt2_init_past_{args.precision}.onnx" gpt2_init_decoder_onnx_path = Path(Path(args.output).parent, gpt2_init_decoder_onnx_filename).as_posix() gpt2_init_decoder_generated = generate_gpt2_init_decoder( - args.decoder_onnx, gpt2_init_decoder_onnx_path, args.use_external_data_format + args.decoder_onnx, + gpt2_init_decoder_onnx_path, + args.use_external_data_format, ) if not gpt2_init_decoder_generated: @@ -2372,7 +2789,8 @@ def convert_generation_model(args: argparse.Namespace, generation_type: Generati logger.info(f"Symbolic shape inference on {args.encoder_decoder_init_onnx}. The file will be overwritten.") shape_inference(args.encoder_decoder_init_onnx, args.use_external_data_format) encoder_model = onnx.load_model(args.encoder_decoder_init_onnx, load_external_data=True) - encoder_model.graph.name = f"{args.model_type} encoder and decoder init" + suffix = "encoder" if len(encoder_model.graph.input) == 2 else "encoder and decoder init" + encoder_model.graph.name = f"{args.model_type} {suffix}" verify_t5_encoder_decoder_init_subgraph(encoder_model.graph, args.precision) make_dim_proto_numeric_t5(encoder_model, config) @@ -2411,14 +2829,13 @@ def convert_generation_model(args: argparse.Namespace, generation_type: Generati # ) # initializers.extend(moved_initializers) + assert config.decoder_start_token_id >= 0, "decoder_start_token_id should be >= 0" + node.attribute.extend( [ onnx.helper.make_attribute("encoder", encoder_model.graph), onnx.helper.make_attribute("decoder", decoder_model.graph), - onnx.helper.make_attribute( - "decoder_start_token_id", - config.decoder_start_token_id if len(encoder_model.graph.input) == 3 else -1, - ), + onnx.helper.make_attribute("decoder_start_token_id", config.decoder_start_token_id), ] ) else: @@ -2538,7 +2955,9 @@ def convert_generation_model(args: argparse.Namespace, generation_type: Generati if args.output_sequences_scores: sequences_scores = onnx.helper.make_tensor_value_info( - "sequences_scores", TensorProto.FLOAT, ["batch_size", "num_return_sequences"] + "sequences_scores", + TensorProto.FLOAT, + ["batch_size", "num_return_sequences"], ) graph_outputs.append(sequences_scores) @@ -2552,7 +2971,7 @@ def convert_generation_model(args: argparse.Namespace, generation_type: Generati new_graph = onnx.helper.make_graph( [node], - f"{args.model_type} beam search" if not is_greedysearch else f"{args.model_type} greedy search", + (f"{args.model_type} beam search" if not is_greedysearch else f"{args.model_type} greedy search"), graph_inputs, graph_outputs, initializers, @@ -2612,7 +3031,7 @@ def test_torch_performance( if args.use_gpu and not torch.cuda.is_available(): raise RuntimeError("Please install PyTorch with Cuda for testing gpu performance.") - if args.precision == Precision.FLOAT16: + if args.precision == Precision.FLOAT16.value: model.half() device = torch.device("cuda:0" if args.use_gpu else "cpu") @@ -2661,7 +3080,11 @@ def create_attention_mask(input_ids, pad_token_id): return attention_mask -def test_gpt_model(args: argparse.Namespace, sentences: list[str] | None = None, is_greedy: bool = False): +def test_gpt_model( + args: argparse.Namespace, + sentences: list[str] | None = None, + is_greedy: bool = False, +): """Test GPT-2 model Args: @@ -2852,7 +3275,7 @@ def test_gpt_model(args: argparse.Namespace, sentences: list[str] | None = None, print("-" * 50) # Compare the generated text instead of word IDs since ORT pads to max sequence length but Torch not. is_same = torch_decoded_sequences == ort_decoded_sequences - print("Torch and ORT result is ", "same" if is_same else "different") + print("Torch and ORT result is", "same" if is_same else "different") output["parity"] = is_same if args.torch_performance: diff --git a/onnxruntime/python/tools/transformers/fusion_attention.py b/onnxruntime/python/tools/transformers/fusion_attention.py index 6a15db20f44ed..5e1d491daae23 100644 --- a/onnxruntime/python/tools/transformers/fusion_attention.py +++ b/onnxruntime/python/tools/transformers/fusion_attention.py @@ -541,6 +541,7 @@ def create_multihead_attention_node( output: str, key_padding_mask: str = "", add_qk: str = "", + unidirectional: bool = False, past_k: str = "", past_v: str = "", present_k: str = "", @@ -561,6 +562,7 @@ def create_multihead_attention_node( output (str): output name of MHA key_padding_mask (str): name of key padding mask add_qk (str): name of add after Q x K' + unidirectional (bool): whether to apply causal attention mask automatically or not past_k (str): name of past K value - (batch_size, num_heads, past_sequence_length, head_size) past_v (str): name of past V value - (batch_size, num_heads, past_sequence_length, head_size) present_k (str): name of present K value - (batch_size, num_heads, sequence_length, head_size) @@ -623,7 +625,6 @@ def create_multihead_attention_node( mha_inputs.append("") # Add optional inputs for MHA - if past_k and past_v: mha_inputs.extend([key_padding_mask, add_qk, past_k, past_v]) elif key_padding_mask or add_qk: @@ -641,7 +642,11 @@ def create_multihead_attention_node( name=mha_node_name, ) mha_node.domain = "com.microsoft" - mha_node.attribute.extend([helper.make_attribute("num_heads", num_heads)]) + mha_node.attribute.append(helper.make_attribute("num_heads", num_heads)) + if unidirectional: + mha_node.attribute.append(helper.make_attribute("unidirectional", int(unidirectional))) + + self.increase_counter("MultiHeadAttention") return mha_node def create_attention_node( @@ -821,6 +826,8 @@ def create_attention_node( outputs=[output], name=attention_node_name, ) + self.increase_counter("MultiHeadAttention") + else: attention_inputs = [ first_input, @@ -855,6 +862,7 @@ def create_attention_node( outputs=attention_outputs, name=attention_node_name, ) + self.increase_counter("Attention") attention_node.domain = "com.microsoft" attention_node.attribute.extend([helper.make_attribute("num_heads", num_heads)]) diff --git a/onnxruntime/python/tools/transformers/fusion_attention_clip.py b/onnxruntime/python/tools/transformers/fusion_attention_clip.py index 63bf6410f86c3..fe93f5cd358bf 100644 --- a/onnxruntime/python/tools/transformers/fusion_attention_clip.py +++ b/onnxruntime/python/tools/transformers/fusion_attention_clip.py @@ -126,7 +126,10 @@ def fuse(self, normalize_node, input_name_to_nodes, output_name_to_node): if node_before_layer_norm is None: continue child = self.model.find_first_child_by_type( - node_before_layer_norm, "LayerNormalization", input_name_to_nodes, False + node_before_layer_norm, + "LayerNormalization", + input_name_to_nodes, + False, ) if child is None: continue @@ -146,19 +149,26 @@ def fuse(self, normalize_node, input_name_to_nodes, output_name_to_node): qkv_nodes = self.model.match_parent_path( normalize_node, ["Add", "MatMul", "Reshape", "Transpose", "MatMul"], - [1, 1, 0, 0, 0], + [1, None, 0, 0, 0], ) if qkv_nodes is None: logger.debug("fuse_attention: failed to match qkv path") return - - reshape_qkv, transpose_qkv, matmul_qkv = qkv_nodes[2], qkv_nodes[3], qkv_nodes[-1] + reshape_qkv, transpose_qkv, matmul_qkv = ( + qkv_nodes[2], + qkv_nodes[3], + qkv_nodes[-1], + ) v_nodes = self.model.match_parent_path( - matmul_qkv, ["Reshape", "Transpose", "Reshape", "Add", "MatMul"], [1, 0, 0, 0, None] + matmul_qkv, + ["Reshape", "Transpose", "Reshape", "Add", "MatMul"], + [1, 0, 0, 0, None], ) if v_nodes is None: - v_nodes = self.model.match_parent_path(matmul_qkv, ["Transpose", "Reshape", "Add", "MatMul"], [1, 0, 0, 1]) + v_nodes = self.model.match_parent_path( + matmul_qkv, ["Transpose", "Reshape", "Add", "MatMul"], [1, 0, 0, None] + ) if v_nodes is None: logger.debug("fuse_attention: failed to match v path") return @@ -182,17 +192,30 @@ def fuse(self, normalize_node, input_name_to_nodes, output_name_to_node): ) if qk_nodes is None: qk_nodes = self.model.match_parent_path(matmul_qkv, ["Softmax", "Add", "Mul", "MatMul"], [0, 0, 0, 0]) - if qk_nodes is None: - qk_nodes = self.model.match_parent_path( - matmul_qkv, ["Cast", "Cast", "Softmax", "Add", "Mul", "MatMul"], [0, 0, 0, 0, 0, 0] - ) - if qk_nodes is None: - logger.debug("fuse_attention: failed to match qk path") - return - else: - add_mask = qk_nodes[3] - else: + if qk_nodes is not None: add_mask = qk_nodes[1] + else: + # If attention mask is not used, we can still match the qk path. + qk_nodes = self.model.match_parent_path(matmul_qkv, ["Softmax", "Mul", "MatMul"], [0, 0, 0]) + if qk_nodes is None: + # Cast nodes are added in the model for fp16. + qk_nodes = self.model.match_parent_path( + matmul_qkv, + ["Cast", "Cast", "Softmax", "Add", "Mul", "MatMul"], + [0, 0, 0, 0, 0, 0], + ) + if qk_nodes is not None: + add_mask = qk_nodes[3] + else: + # If attention mask is not used, we can still match the qk path. + qk_nodes = self.model.match_parent_path( + matmul_qkv, + ["Cast", "Cast", "Softmax", "Mul", "MatMul"], + [0, 0, 0, 0, 0], + ) + if qk_nodes is None: + logger.debug("fuse_attention: failed to match qk path") + return else: assert len(add_mask_indices) == 1 causal_mask_input_index = 1 - add_mask_indices[0] @@ -201,10 +224,14 @@ def fuse(self, normalize_node, input_name_to_nodes, output_name_to_node): matmul_qk = qk_nodes[-1] q_nodes = self.model.match_parent_path( - matmul_qk, ["Reshape", "Transpose", "Reshape", "Mul", "Add", "MatMul"], [0, 0, 0, 0, None, None] + matmul_qk, + ["Reshape", "Transpose", "Reshape", "Mul", "Add", "MatMul"], + [0, 0, 0, 0, None, None], ) if q_nodes is None: - q_nodes = self.model.match_parent_path(matmul_qk, ["Transpose", "Reshape", "Add", "MatMul"], [0, 0, 0, 1]) + q_nodes = self.model.match_parent_path( + matmul_qk, ["Transpose", "Reshape", "Add", "MatMul"], [0, 0, 0, None] + ) if q_nodes is None: logger.debug("fuse_attention: failed to match q path") return @@ -216,10 +243,14 @@ def fuse(self, normalize_node, input_name_to_nodes, output_name_to_node): add_q, matmul_q = q_nodes[-2], q_nodes[-1] k_nodes = self.model.match_parent_path( - matmul_qk, ["Transpose", "Reshape", "Transpose", "Reshape", "Add", "MatMul"], [1, 0, 0, 0, 0, None] + matmul_qk, + ["Transpose", "Reshape", "Transpose", "Reshape", "Add", "MatMul"], + [1, 0, 0, 0, 0, None], ) if k_nodes is None: - k_nodes = self.model.match_parent_path(matmul_qk, ["Transpose", "Reshape", "Add", "MatMul"], [1, 0, 0, 1]) + k_nodes = self.model.match_parent_path( + matmul_qk, ["Transpose", "Reshape", "Add", "MatMul"], [1, 0, 0, None] + ) if k_nodes is None: logger.debug("fuse_attention: failed to match k path") return @@ -242,7 +273,17 @@ def fuse(self, normalize_node, input_name_to_nodes, output_name_to_node): # 4D Add after Q x K' add_qk_nodes = self.model.match_parent_path( add_mask, - ["Where", "Sub", "Cast", "Expand", "Unsqueeze", "Unsqueeze", "Reshape", "Reshape", "Cast"], + [ + "Where", + "Sub", + "Cast", + "Expand", + "Unsqueeze", + "Unsqueeze", + "Reshape", + "Reshape", + "Cast", + ], [1, 2, 1, 0, 0, 0, 0, 0, 0], ) if add_qk_nodes is not None: diff --git a/onnxruntime/python/tools/transformers/fusion_bart_attention.py b/onnxruntime/python/tools/transformers/fusion_bart_attention.py index 69445f93e683d..45bbfa94f6aa2 100644 --- a/onnxruntime/python/tools/transformers/fusion_bart_attention.py +++ b/onnxruntime/python/tools/transformers/fusion_bart_attention.py @@ -82,14 +82,11 @@ def check_runtime_shape_path_openai( matmul_qk, add_q, ): - reshape_qkv_2_path = self.model.match_parent_path( - reshape_qkv_2, ["Concat", "Slice", "Gather", "Shape"], [1, 0, 0, 0] + reshape_qkv_path = self.model.match_parent_path( + reshape_qkv_2, ["Concat", "Slice", "Shape", "Transpose"], [1, 0, 0, 0] ) - if reshape_qkv_2_path is None: + if reshape_qkv_path is None or reshape_qkv_path[-1].input[0] != matmul_qkv.output[0]: return False - else: - if reshape_qkv_2_path[-1].input[0] != matmul_qkv.output[0]: - return False matmul_qk_path_1 = self.model.match_parent_path( matmul_qk, ["Mul", "Pow", "Cast", "Div", "Gather", "Shape"], [0, 1, 0, 0, 0, 0] @@ -348,7 +345,7 @@ def fuse(self, normalize_node, input_name_to_nodes, output_name_to_node): ["Transpose", "Reshape", "Transpose", "Reshape", "Add", "MatMul"], [1, 0, 0, 0, 0, 1], ) - k_nodes_with_bias_openai = self.model.match_parent_path( + k_nodes_no_bias_openai = self.model.match_parent_path( matmul_qk, ["Mul", "Transpose", "Reshape", "MatMul"], [1, 0, 0, 0], @@ -381,9 +378,9 @@ def fuse(self, normalize_node, input_name_to_nodes, output_name_to_node): if k_nodes_with_bias is not None: _, reshape_k_2, transpose_k_1, reshape_k_1, add_k, matmul_k = k_nodes_with_bias k_nodes = k_nodes_with_bias - elif k_nodes_with_bias_openai is not None: - mul_k, transpose_k_1, reshape_k_1, matmul_k = k_nodes_with_bias_openai - k_nodes = k_nodes_with_bias_openai + elif k_nodes_no_bias_openai is not None: + mul_k, transpose_k_1, reshape_k_1, matmul_k = k_nodes_no_bias_openai + k_nodes = k_nodes_no_bias_openai present_k = matmul_k.output[0] # Find the child path to access the correct present_k values @@ -403,7 +400,7 @@ def fuse(self, normalize_node, input_name_to_nodes, output_name_to_node): # \ / # -> Concat <- # | - # |--> Reshape -> Transpose -> Present_K + # +--> Reshape -> Transpose -> Present_K concat_path = self.model.match_child_path(matmul_k, ["Concat", "Reshape", "Transpose"]) if reshape_path is not None: (_, transpose_matmul_k) = reshape_path @@ -455,7 +452,7 @@ def fuse(self, normalize_node, input_name_to_nodes, output_name_to_node): past_k = past_k if past_k in graph_input_names else "" present_k = present_k if present_k in graph_output_names else "" - if k_nodes in (k_nodes_with_bias_openai, k_nodes_no_bias, k_nodes_no_bias_with_past_self_attn): + if k_nodes in (k_nodes_no_bias_openai, k_nodes_no_bias, k_nodes_no_bias_with_past_self_attn): # Create empty Add node for attention graph bias_dim = self.model.get_initializer(add_v.input[0]).dims[0] empty_bias_name = "empty_bias" @@ -473,7 +470,7 @@ def fuse(self, normalize_node, input_name_to_nodes, output_name_to_node): if ( model_impl_openai - and not past_k + and not bool(past_k) and not self.check_runtime_shape_path_openai( reshape_qkv_2, matmul_qkv, @@ -485,7 +482,7 @@ def fuse(self, normalize_node, input_name_to_nodes, output_name_to_node): return elif ( not model_impl_openai - and not past_k + and not bool(past_k) and not self.check_runtime_shape_path( reshape_qkv_2, reshape_qkv_1, @@ -497,7 +494,7 @@ def fuse(self, normalize_node, input_name_to_nodes, output_name_to_node): ): return - three_root_inputs = past_k and past_v and matmul_k is None and "matmul_v" not in locals() + three_root_inputs = bool(past_k) and bool(past_v) and matmul_k is None and "matmul_v" not in locals() one_root_input = ( not three_root_inputs and matmul_k.input[0] == root_input @@ -520,13 +517,13 @@ def fuse(self, normalize_node, input_name_to_nodes, output_name_to_node): encoder_attention = one_root_input and qk_nodes == qk_nodes_1 decoder_attention = one_root_input and qk_nodes in (qk_nodes_2, qk_nodes_2_openai) decoder_attention_with_past = ( - (encoder_attention if not model_impl_openai else decoder_attention) and past_k and past_v + (encoder_attention if not model_impl_openai else decoder_attention) and bool(past_k) and bool(past_v) ) decoder_cross_attention = two_root_inputs and qk_nodes == qk_nodes_1 decoder_cross_attention_with_past = three_root_inputs and qk_nodes == qk_nodes_1 # For decoder_attention, the attention mask needs to be included in the attention node - mask_index = None + mask_index, mask_nodes = None, [] if decoder_attention: mask_nodes_bart = self.model.match_parent_path( add_qk, @@ -540,8 +537,10 @@ def fuse(self, normalize_node, input_name_to_nodes, output_name_to_node): ) if mask_nodes_whisper is not None: mask_index = mask_nodes_whisper[0].output[-1] + mask_nodes = mask_nodes_whisper elif mask_nodes_bart is not None: mask_index = mask_nodes_bart[0].output[-1] + mask_nodes = mask_nodes_bart if ( encoder_attention @@ -573,6 +572,7 @@ def fuse(self, normalize_node, input_name_to_nodes, output_name_to_node): num_heads=num_heads, hidden_size=hidden_size, output=attention_last_node.output[0], + unidirectional=decoder_attention_with_past, past_k=past_k if decoder_attention_with_past else "", past_v=past_v if decoder_attention_with_past else "", present_k=present_k, @@ -599,11 +599,14 @@ def fuse(self, normalize_node, input_name_to_nodes, output_name_to_node): hidden_size=hidden_size, first_input=root_input, output=attention_last_node.output[0], - add_qk_str=add_qk_str, + add_qk_str=( + None if len(mask_nodes) > 1 else add_qk_str + ), # deprecate and use is_unidirectional attr instead for Whisper past_k=past_k, past_v=past_v, present_k=present_k, present_v=present_v, + causal=decoder_attention, ) self.use_multi_head_attention = use_multi_head_attention_ground_truth if new_node is None: diff --git a/onnxruntime/python/tools/transformers/fusion_fastgelu.py b/onnxruntime/python/tools/transformers/fusion_fastgelu.py index 210f10e2eadd4..728bd03244758 100644 --- a/onnxruntime/python/tools/transformers/fusion_fastgelu.py +++ b/onnxruntime/python/tools/transformers/fusion_fastgelu.py @@ -177,13 +177,12 @@ def fuse_2(self, tanh_node, input_name_to_nodes: dict, output_name_to_node: dict return mul_after_mul_half = children[0] + # root_node could be None when root_input is graph input root_node = self.model.get_parent( mul_after_mul_half, 0 if mul_after_mul_half.input[1] == mul_half.output[0] else 1, output_name_to_node, ) - if root_node is None: - return mul_before_tanh = self.model.match_parent(tanh_node, "Mul", 0, output_name_to_node) if mul_before_tanh is None: @@ -197,7 +196,13 @@ def fuse_2(self, tanh_node, input_name_to_nodes: dict, output_name_to_node: dict if add_before_tanh is None: return - mul_after_pow = self.model.match_parent(add_before_tanh, "Mul", None, output_name_to_node, exclude=[root_node]) + mul_after_pow = self.model.match_parent( + add_before_tanh, + "Mul", + None, + output_name_to_node, + exclude=[root_node] if root_node else [], + ) if mul_after_pow is None: return @@ -212,7 +217,9 @@ def fuse_2(self, tanh_node, input_name_to_nodes: dict, output_name_to_node: dict if not self.model.has_constant_input(pow, 3.0): return - if pow.input[0] != root_node.output[0]: + root_input = mul_after_mul_half.input[0 if mul_after_mul_half.input[1] == mul_half.output[0] else 1] + + if pow.input[0] != root_input: return subgraph_nodes = [ @@ -236,7 +243,7 @@ def fuse_2(self, tanh_node, input_name_to_nodes: dict, output_name_to_node: dict self.nodes_to_remove.extend(subgraph_nodes) fused_node = helper.make_node( "FastGelu", - inputs=[root_node.output[0]], + inputs=[root_input], outputs=mul_after_mul_half.output, name=self.model.create_node_name("FastGelu"), ) diff --git a/onnxruntime/python/tools/transformers/fusion_simplified_layernorm.py b/onnxruntime/python/tools/transformers/fusion_simplified_layernorm.py index a0eff081675fe..5ce089712ccb1 100644 --- a/onnxruntime/python/tools/transformers/fusion_simplified_layernorm.py +++ b/onnxruntime/python/tools/transformers/fusion_simplified_layernorm.py @@ -51,6 +51,7 @@ def fuse(self, node, input_name_to_nodes: dict, output_name_to_node: dict): mul_node, div_node, _sqrt_node, add_node, reduce_mean_node = sim_ln_nodes if not self.model.has_constant_input(div_node, 1.0): return + node_parent = mul_node else: # Div(1, RMS) can also be represented as Reciprocal(RMS) like # @@ -66,6 +67,7 @@ def fuse(self, node, input_name_to_nodes: dict, output_name_to_node: dict): # Mul --> ReduceMean --> Add ---> Sqrt --> Reciprocal --> Mul --> Mul (node) # (B=2) (A/B=eps) (A/B=scale) # + return_indice = [] sim_ln_nodes = self.model.match_parent_path( node, ["Mul", "Reciprocal", "Sqrt", "Add", "ReduceMean"], @@ -73,24 +75,50 @@ def fuse(self, node, input_name_to_nodes: dict, output_name_to_node: dict): output_name_to_node=output_name_to_node, return_indice=return_indice, ) - if sim_ln_nodes is None: - return - mul_node, _reciprocal_node, _sqrt_node, add_node, reduce_mean_node = sim_ln_nodes - - pow_or_mul_node = self.model.get_parent(reduce_mean_node, 0, output_name_to_node) - if pow_or_mul_node is None or pow_or_mul_node.op_type not in ["Pow", "Mul"]: + if sim_ln_nodes is not None: + mul_node, _reciprocal_node, _sqrt_node, add_node, reduce_mean_node = sim_ln_nodes + node_parent = mul_node + else: + # (root_input) --------------------------------+ + # | | + # v v + # Pow --> ReduceMean --> Add ---> Sqrt --> Div --> Mul (node) + # (B=2) (A/B=eps) (A/B=scale) + # + # (root_input) --------------------------------+ + # | | | + # v v v + # Mul --> ReduceMean --> Add ---> Sqrt --> Div --> Mul (node) + # (B=2) (A/B=eps) (A/B=scale) + # + return_indice = [] + sim_ln_nodes = self.model.match_parent_path( + node, + ["Div", "Sqrt", "Add", "ReduceMean"], + [None, 1, 0, None], + output_name_to_node=output_name_to_node, + return_indice=return_indice, + ) + if sim_ln_nodes is not None: + div_node, _sqrt_node, add_node, reduce_mean_node = sim_ln_nodes + node_parent = div_node + else: + return + + reduce_mean_parent = self.model.get_parent(reduce_mean_node, 0, output_name_to_node) + if reduce_mean_parent is None or reduce_mean_parent.op_type not in ["Pow", "Mul"]: return - if pow_or_mul_node.op_type == "Pow": - if self.model.find_constant_input(pow_or_mul_node, 2.0) != 1: + if reduce_mean_parent.op_type == "Pow": + if self.model.find_constant_input(reduce_mean_parent, 2.0) != 1: return else: - assert pow_or_mul_node.op_type == "Mul" - if pow_or_mul_node[0] != pow_or_mul_node[1]: + assert reduce_mean_parent.op_type == "Mul" + if reduce_mean_parent[0] != reduce_mean_parent[1]: return - root_input = pow_or_mul_node.input[0] - if root_input != mul_node.input[0]: + root_input = reduce_mean_parent.input[0] + if root_input not in node_parent.input: return _i, epsilon = self.model.get_constant_input(add_node) @@ -113,7 +141,7 @@ def fuse(self, node, input_name_to_nodes: dict, output_name_to_node: dict): return self.nodes_to_remove.extend(sim_ln_nodes) - self.nodes_to_remove.append(pow_or_mul_node) + self.nodes_to_remove.append(reduce_mean_parent) self.nodes_to_remove.append(node) normalize_node = helper.make_node( diff --git a/onnxruntime/python/tools/transformers/models/gpt2/convert_to_onnx.py b/onnxruntime/python/tools/transformers/models/gpt2/convert_to_onnx.py index 75887cc744081..f8b7dd80710ae 100644 --- a/onnxruntime/python/tools/transformers/models/gpt2/convert_to_onnx.py +++ b/onnxruntime/python/tools/transformers/models/gpt2/convert_to_onnx.py @@ -371,9 +371,6 @@ def main(argv=None, experiment_name: str = "", run_id: str = "0", csv_filename: model_size_in_MB = int(get_onnx_model_size(output_path, args.use_external_data_format) / 1024 / 1024) # noqa: N806 provider = args.provider - if args.provider == "migraphx": - provider = "MIGraphXExecutionProvider" - session = create_onnxruntime_session( output_path, args.use_gpu, provider, enable_all_optimization=True, verbose=args.verbose ) diff --git a/onnxruntime/python/tools/transformers/models/sam2/README.md b/onnxruntime/python/tools/transformers/models/sam2/README.md index e7cafeffc6231..463d154525f8f 100644 --- a/onnxruntime/python/tools/transformers/models/sam2/README.md +++ b/onnxruntime/python/tools/transformers/models/sam2/README.md @@ -96,8 +96,7 @@ We can create a conda environment then run GPU benchmark like the following: conda create -n sam2_gpu python=3.11 -y conda activate sam2_gpu install_dir=$HOME -profiling=true -bash benchmark_sam2.sh $install_dir gpu $profiling +bash benchmark_sam2.sh $install_dir gpu ``` or create a new conda environment for CPU benchmark: @@ -107,16 +106,28 @@ conda activate sam2_cpu bash benchmark_sam2.sh $HOME cpu ``` -The first parameter is a directory to clone git repositories or install CUDA/cuDNN for benchmark. -The second parameter can be either "gpu" or "cpu", which indicates the device to run benchmark. -The third parameter is optional. Value "true" will enable profiling after running benchmarking on GPU. +The usage of the script like the following: +``` +bash benchmark_sam2.sh [profiling] [benchmarking] [nightly] [dynamo] +``` + +| Parameter| Default | Description | +|----------|----------| ------------| +| install_dir | $HOME | a directory to clone git repositories or install CUDA/cuDNN for benchmark | +| cpu_or_gpu | gpu | the device to run benchmark. The value can be either "gpu" or "cpu" | +| profiling | false | run gpu profiling | +| benchmarking | true | run benchmark | +| nightly | false | install onnxruntime nightly or official release package | +| dynamo | false | export image encoder using dynamo or not. | -The script will automatically install required packages in current conda environment, download checkpoints, export onnx, -and run demo, benchmark and optionally run profiling. +The dynamo export is experimental since graph optimization still need extra works for this model. -* The performance test result is in sam2_gpu.csv or sam2_cpu.csv, which can be loaded into Excel. -* The demo output is sam2_demo_fp16_gpu.png or sam2_demo_fp32_cpu.png. -* The profiling results are in *.nsys-rep or *.json files in current directory. Use Nvidia NSight System to view the *.nsys-rep file. +Output files: +* sam2_cpu_[timestamp].csv or sam2_gpu_[timestamp].csv has benchmark results. Use Excel to load the file to view it. +* onnxruntime_image_[encoder|decoder].json has ONNX Runtime profiling results. Use `chrome://tracing` in Chrome browser to view it. +* torch_image_[encoder|decoder].json has PyTorch profiling results. Use `chrome://tracing` in Chrome browser to view it. +* sam2_fp16_profile_image_[encoder|decoder]_[ort|torch]_gpu.[nsys-rep|sqlite] has NVTX profiling. Use Nvidia NSight System to view it. +* torch_image_encoder_compiled_code.txt has the compiled kernel code from Pytorch. ## Limitations - The exported image_decoder model does not support batch mode for now. diff --git a/onnxruntime/python/tools/transformers/models/sam2/benchmark_sam2.py b/onnxruntime/python/tools/transformers/models/sam2/benchmark_sam2.py index 16d71d5057b02..3fc24d157b0cf 100644 --- a/onnxruntime/python/tools/transformers/models/sam2/benchmark_sam2.py +++ b/onnxruntime/python/tools/transformers/models/sam2/benchmark_sam2.py @@ -46,6 +46,7 @@ def __init__( prefer_nhwc: bool = False, warm_up: int = 5, enable_nvtx_profile: bool = False, + enable_ort_profile: bool = False, enable_torch_profile: bool = False, repeats: int = 1000, verbose: bool = False, @@ -74,6 +75,7 @@ def __init__( self.prefer_nhwc = prefer_nhwc self.warm_up = warm_up self.enable_nvtx_profile = enable_nvtx_profile + self.enable_ort_profile = enable_ort_profile self.enable_torch_profile = enable_torch_profile self.repeats = repeats self.verbose = verbose @@ -317,6 +319,7 @@ def run_test( repeats=args.repeats, warm_up=args.warm_up, enable_nvtx_profile=args.enable_nvtx_profile, + enable_ort_profile=args.enable_ort_profile, enable_torch_profile=args.enable_torch_profile, torch_compile_mode=args.torch_compile_mode, verbose=False, @@ -325,7 +328,7 @@ def run_test( if args.engine == "ort": sess_options = SessionOptions() sess_options.intra_op_num_threads = args.intra_op_num_threads - if config.enable_nvtx_profile: + if config.enable_ort_profile: sess_options.enable_profiling = True sess_options.log_severity_level = 4 sess_options.log_verbosity_level = 0 @@ -349,6 +352,8 @@ def run_test( with nvtx.annotate("one_run"): _ = session.infer(input_dict) cudart.cudaProfilerStop() + + if config.enable_ort_profile: session.ort_session.end_profiling() if repeats == 0: @@ -554,6 +559,14 @@ def _parse_arguments(): help="Enable nvtx profiling. It will add an extra run for profiling before performance test.", ) + parser.add_argument( + "--enable_ort_profile", + required=False, + default=False, + action="store_true", + help="Enable ORT profiling.", + ) + parser.add_argument( "--enable_torch_profile", required=False, diff --git a/onnxruntime/python/tools/transformers/models/sam2/benchmark_sam2.sh b/onnxruntime/python/tools/transformers/models/sam2/benchmark_sam2.sh index 9e97867657ab9..c82b1ed31796e 100644 --- a/onnxruntime/python/tools/transformers/models/sam2/benchmark_sam2.sh +++ b/onnxruntime/python/tools/transformers/models/sam2/benchmark_sam2.sh @@ -5,7 +5,17 @@ # ------------------------------------------------------------------------- # Please refer to README.md for the prerequisites and usage of this script. -# bash benchmark_sam2.sh [profiling] +# bash benchmark_sam2.sh [profiling] [benchmarking] [nightly] [dynamo] +# Note that dynamo need onnxruntime 1.21 or later, or nightly build. +# Example: +# bash benchmark_sam2.sh $HOME gpu true true true false + +install_dir="${1:-$HOME}" +cpu_or_gpu="${2:-gpu}" +profiling="${3:-false}" +benchmarking="${4:-true}" +nightly="${5:-false}" +dynamo="${6:-false}" python="$CONDA_PREFIX/bin/python3" @@ -13,9 +23,6 @@ python="$CONDA_PREFIX/bin/python3" dir="$(cd "$(dirname "$0")" && pwd)" onnx_dir="$dir/sam2_onnx_models" -# Installation directory (default: $HOME) -install_dir="${1:-$HOME}" - if [ ! -d "$install_dir" ]; then echo "Error: install_dir '$install_dir' does not exist." exit 1 @@ -26,7 +33,6 @@ sam2_dir="$install_dir/segment-anything-2" model="sam2_hiera_large" # Default to GPU, switch to CPU if specified -cpu_or_gpu="${2:-gpu}" if [ "$cpu_or_gpu" != "gpu" ] && [ "$cpu_or_gpu" != "cpu" ]; then echo "Invalid option: $2. Please specify 'cpu' or 'gpu'." exit 1 @@ -35,52 +41,97 @@ fi echo "install_dir: $install_dir" echo "cpu_or_gpu: $cpu_or_gpu" -install_cuda_12() -{ - pushd $install_dir - wget https://developer.download.nvidia.com/compute/cuda/12.6.2/local_installers/cuda_12.6.2_560.35.03_linux.run - sh cuda_12.6.2_560.35.03_linux.run --toolkit --toolkitpath=$install_dir/cuda12.6 --silent --override --no-man-page +# Function to check if a command exists +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# Ensure necessary tools are installed +if ! command_exists wget; then + echo "wget is not installed. Please install it and try again." + exit 1 +fi + +if ! command_exists git; then + echo "git is not installed. Please install it and try again." + exit 1 +fi + +if ! command_exists pip; then + echo "pip is not installed. Please install it and try again." + exit 1 +fi + +cuda_version=12.6 +cudnn_version=9.5 - export PATH="$install_dir/cuda12.6/bin:$PATH" - export LD_LIBRARY_PATH="$install_dir/cuda12.6/lib64:$LD_LIBRARY_PATH" - popd +# Install CUDA 12.6 +install_cuda_12() { + if ! [ -d "$install_dir/cuda${cuda_version}" ]; then + pushd "$install_dir" || exit + wget https://developer.download.nvidia.com/compute/cuda/12.6.2/local_installers/cuda_12.6.2_560.35.03_linux.run + sh cuda_12.6.2_560.35.03_linux.run --toolkit --toolkitpath="$install_dir/cuda${cuda_version}" --silent --override --no-man-page + popd || exit + fi + export PATH="$install_dir/cuda${cuda_version}/bin:$PATH" + export LD_LIBRARY_PATH="$install_dir/cuda${cuda_version}/lib64:$LD_LIBRARY_PATH" } -# Function to install cuDNN 9.4 +# Install cuDNN 9.5 install_cudnn_9() { - pushd "$install_dir" - wget -q https://developer.download.nvidia.com/compute/cudnn/redist/cudnn/linux-x86_64/cudnn-linux-x86_64-9.5.0.50_cuda12-archive.tar.xz - mkdir -p "$install_dir/cudnn9.5" - tar -Jxvf cudnn-linux-x86_64-9.5.0.50_cuda12-archive.tar.xz -C "$install_dir/cudnn9.5" --strip=1 - export LD_LIBRARY_PATH="$install_dir/cudnn9.5/lib:$LD_LIBRARY_PATH" - popd + if ! [ -d "$install_dir/cudnn${cudnn_version}" ]; then + pushd "$install_dir" || exit + wget -q https://developer.download.nvidia.com/compute/cudnn/redist/cudnn/linux-x86_64/cudnn-linux-x86_64-9.5.0.50_cuda12-archive.tar.xz + mkdir -p "$install_dir/cudnn${cudnn_version}" + tar -Jxvf cudnn-linux-x86_64-9.5.0.50_cuda12-archive.tar.xz -C "$install_dir/cudnn${cudnn_version}" --strip=1 + popd || exit + fi + export LD_LIBRARY_PATH="$install_dir/cudnn${cudnn_version}/lib:$LD_LIBRARY_PATH" +} + +install_ort() { + local ort="$1" + pip uninstall onnxruntime onnxruntime-gpu -y + + if [ "$nightly" = "true" ]; then + pip install flatbuffers numpy packaging protobuf sympy + pip install --pre --index-url https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/ORT-Nightly/pypi/simple/ "$ort" + else + pip install "$ort" + fi + + pip install onnx onnxscript opencv-python matplotlib } # Install GPU dependencies install_gpu() { - [ ! -d "$install_dir/cuda12.6" ] && install_cuda_12 - [ ! -d "$install_dir/cudnn9.5" ] && install_cudnn_9 + install_cuda_12 + install_cudnn_9 + echo "PATH: $PATH" + echo "LD_LIBRARY_PATH: $LD_LIBRARY_PATH" + + # The dynamo export need torch 2.6.0 or later. Use the latest one. + pip install torch torchvision --index-url https://download.pytorch.org/whl/cu124 --upgrade - pip install torch torchvision --index-url https://download.pytorch.org/whl/cu124 - pip install onnxruntime-gpu onnx opencv-python matplotlib + install_ort "onnxruntime-gpu" } # Install CPU dependencies install_cpu() { pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu - pip install onnxruntime onnx opencv-python matplotlib + install_ort "onnxruntime" } # Clone and install SAM2 if not already installed install_sam2() { - pushd "$install_dir" + pushd "$install_dir" || exit if [ ! -d "$sam2_dir" ]; then git clone https://github.com/facebookresearch/segment-anything-2.git fi - cd "$sam2_dir" + cd "$sam2_dir" || exit pip show SAM-2 > /dev/null 2>&1 || pip install -e . [ ! -f checkpoints/sam2_hiera_large.pt ] && (cd checkpoints && sh ./download_ckpts.sh) - popd + popd || exit } # Download test image if not available @@ -90,7 +141,12 @@ download_test_image() { run_cpu_benchmark() { local repeats="$1" - $python convert_to_onnx.py --sam2_dir "$sam2_dir" --optimize --demo + + if [ "$dynamo" = "true" ]; then + $python convert_to_onnx.py --sam2_dir "$sam2_dir" --optimize --demo --dynamo + else + $python convert_to_onnx.py --sam2_dir "$sam2_dir" --optimize --demo + fi for component in image_encoder image_decoder; do $python benchmark_sam2.py --model_type "$model" --engine torch --sam2_dir "$sam2_dir" --repeats "$repeats" --dtype fp32 --component "$component" @@ -103,65 +159,75 @@ run_cpu_benchmark() { done } -run_gpu_benchmark() { +run_ort_gpu_benchmark() { local repeats="$1" - $python convert_to_onnx.py --sam2_dir "$sam2_dir" --optimize --use_gpu --dtype fp32 - $python convert_to_onnx.py --sam2_dir "$sam2_dir" --optimize --use_gpu --dtype fp16 --demo - for component in image_encoder image_decoder; do - for dtype in bf16 fp32 fp16; do - $python benchmark_sam2.py --model_type "$model" --engine torch --sam2_dir "$sam2_dir" --repeats "$repeats" --use_gpu --dtype $dtype --component "$component" - done - done + if [ "$dynamo" = "true" ]; then + $python convert_to_onnx.py --sam2_dir "$sam2_dir" --optimize --use_gpu --dtype fp32 --dynamo + $python convert_to_onnx.py --sam2_dir "$sam2_dir" --optimize --use_gpu --dtype fp16 --demo --dynamo + else + $python convert_to_onnx.py --sam2_dir "$sam2_dir" --optimize --use_gpu --dtype fp32 + $python convert_to_onnx.py --sam2_dir "$sam2_dir" --optimize --use_gpu --dtype fp16 --demo + fi component="image_encoder" for dtype in fp32 fp16; do - #TODO: --prefer_nhwc does not help with performance - $python benchmark_sam2.py --model_type "$model" --engine ort --sam2_dir "$sam2_dir" --repeats "$repeats" --use_gpu --dtype $dtype --component "$component" --onnx_path "${onnx_dir}/${model}_${component}_${dtype}_gpu.onnx" --use_cuda_graph + $python benchmark_sam2.py --model_type "$model" --engine ort --sam2_dir "$sam2_dir" --repeats "$repeats" --use_gpu --dtype "$dtype" --component "$component" --onnx_path "${onnx_dir}/${model}_${component}_${dtype}_gpu.onnx" --use_cuda_graph done + # Test prefer_nhwc. + $python benchmark_sam2.py --model_type "$model" --engine ort --sam2_dir "$sam2_dir" --repeats "$repeats" --use_gpu --dtype fp16 --component "$component" --onnx_path "${onnx_dir}/${model}_${component}_${dtype}_gpu.onnx" --use_cuda_graph --prefer_nhwc component="image_decoder" for dtype in fp32 fp16; do # TODO: decoder does not work with cuda graph - $python benchmark_sam2.py --model_type "$model" --engine ort --sam2_dir "$sam2_dir" --repeats "$repeats" --use_gpu --dtype $dtype --component "$component" --onnx_path "${onnx_dir}/${model}_${component}_${dtype}_gpu.onnx" + $python benchmark_sam2.py --model_type "$model" --engine ort --sam2_dir "$sam2_dir" --repeats "$repeats" --use_gpu --dtype "$dtype" --component "$component" --onnx_path "${onnx_dir}/${model}_${component}_${dtype}_gpu.onnx" done + # Test prefer_nhwc. + $python benchmark_sam2.py --model_type "$model" --engine ort --sam2_dir "$sam2_dir" --repeats "$repeats" --use_gpu --dtype fp16 --component "$component" --onnx_path "${onnx_dir}/${model}_${component}_${dtype}_gpu.onnx" --prefer_nhwc } -run_torch_compile_gpu_benchmark() { +run_torch_gpu_benchmark() { local repeats="$1" + # Test PyTorch eager mode. + for component in image_encoder image_decoder; do + for dtype in bf16 fp32 fp16; do + $python benchmark_sam2.py --model_type "$model" --engine torch --sam2_dir "$sam2_dir" --repeats "$repeats" --use_gpu --dtype "$dtype" --component "$component" + done + done + # Test different torch compile modes on image encoder for torch_compile_mode in none max-autotune reduce-overhead max-autotune-no-cudagraphs do - $python benchmark_sam2.py --model_type $model --engine torch --sam2_dir "$sam2_dir" --repeats "$repeats" --use_gpu --dtype fp16 --component image_encoder --torch_compile_mode $torch_compile_mode + $python benchmark_sam2.py --model_type "$model" --engine torch --sam2_dir "$sam2_dir" --repeats "$repeats" --use_gpu --dtype fp16 --component image_encoder --torch_compile_mode $torch_compile_mode done } - -# Main script -run_benchmarks() { - if [ ! -v CONDA_PREFIX ]; then - echo "Please activate conda environment before running this script." - exit 1 +install_all() { + if [ "$cpu_or_gpu" = "gpu" ]; then + install_gpu + else + install_cpu fi - - # Install dependencies - [ "$cpu_or_gpu" = "gpu" ] && install_gpu || install_cpu install_sam2 download_test_image +} - # Run benchmarks - output_csv="sam2_${cpu_or_gpu}.csv" +run_benchmarks() { + suffix=$(date +"%Y_%m_%d_%H_%M_%S") + [ "$dynamo" = "true" ] && suffix="${suffix}_dynamo" + output_csv="sam2_${cpu_or_gpu}_${suffix}.csv" if [ ! -f "$output_csv" ]; then echo "Running $cpu_or_gpu benchmark..." if [ "$cpu_or_gpu" = "gpu" ]; then - run_gpu_benchmark 1000 - run_torch_compile_gpu_benchmark 1000 + run_ort_gpu_benchmark 1000 + run_torch_gpu_benchmark 1000 else run_cpu_benchmark 100 fi cat benchmark*.csv > combined_csv awk '!x[$0]++' combined_csv > "$output_csv" + rm benchmark*.csv rm combined_csv echo "Benchmark results saved in $output_csv" else @@ -169,7 +235,16 @@ run_benchmarks() { fi } -run_benchmarks +if [ ! -v CONDA_PREFIX ]; then + echo "Please activate conda environment before running this script." + exit 1 +fi + +install_all + +if [ "$benchmarking" = "true" ]; then + run_benchmarks +fi #-------------------------------------------------------------------------- # Below are for profiling @@ -177,79 +252,100 @@ run_benchmarks # Build onnxruntime-gpu from source for profiling build_onnxruntime_gpu_for_profiling() { - pushd "$install_dir" + pushd "$install_dir" || exit if ! [ -d onnxruntime ]; then git clone https://github.com/microsoft/onnxruntime fi - cd onnxruntime - CUDA_ARCH=$(python3 -c "import torch; cc = torch.cuda.get_device_capability(); print(f'{cc[0]}{cc[1]}')") - if [ -n "$CUDA_ARCH" ]; then - pip install --upgrade pip cmake psutil setuptools wheel packaging ninja numpy==1.26.4 - sh build.sh --config Release --build_dir build/cuda12 --build_shared_lib --parallel \ - --use_cuda --cuda_version 12.6 --cuda_home $install_dir/cuda12.6 \ - --cudnn_home $install_dir/cudnn9.5 \ - --build_wheel --skip_tests \ - --cmake_generator Ninja \ - --compile_no_warning_as_error \ - --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=$CUDA_ARCH \ - --cmake_extra_defines onnxruntime_ENABLE_NVTX_PROFILE=ON \ - --enable_cuda_line_info - - pip install build/cuda12/Release/dist/onnxruntime_gpu-*-linux_x86_64.whl numpy==1.26.4 - else - echo "No CUDA device found." - exit 1 - fi - popd + cd onnxruntime || exit + pip install --upgrade pip cmake psutil setuptools wheel packaging ninja numpy + build_dir=build/cuda${cuda_version} + rm -rf ${build_dir}/Release/dist + sh build.sh --config Release --build_dir "${build_dir}" --build_shared_lib --parallel \ + --use_cuda --cuda_version ${cuda_version} --cuda_home "$install_dir/cuda${cuda_version}" \ + --cudnn_home "$install_dir/cudnn${cudnn_version}" \ + --build_wheel --skip_tests \ + --cmake_generator Ninja \ + --compile_no_warning_as_error \ + --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=native \ + --cmake_extra_defines onnxruntime_ENABLE_NVTX_PROFILE=ON \ + --enable_cuda_line_info + pip uninstall onnxruntime-gpu -y + pip install "${build_dir}/Release/dist/onnxruntime_gpu-*-linux_x86_64.whl" + popd || exit } # Run profiling with NVTX. -run_nvtx_profile() -{ - pip install nvtx cuda-python==12.6.0 - +run_nvtx_profile() { + local engine="$1" # Only trace one device to avoid huge output file size. device_id=0 - envs="CUDA_VISIBLE_DEVICES=$device_id,ORT_ENABLE_CUDNN_FLASH_ATTENTION=1,LD_LIBRARY_PATH=$LD_LIBRARY_PATH" + envs="CUDA_VISIBLE_DEVICES=$device_id,ORT_ENABLE_CUDNN_FLASH_ATTENTION=1,LD_LIBRARY_PATH=$LD_LIBRARY_PATH,TORCHINDUCTOR_UNIQUE_KERNEL_NAMES=1" cuda_graph_trace=node - for engine in ort torch; do - for component in image_encoder image_decoder; do - sudo $install_dir/cuda12.6/bin/nsys profile --capture-range=nvtx --nvtx-capture='one_run' \ - --gpu-metrics-device $device_id --force-overwrite true \ - --sample process-tree --backtrace fp --stats true \ - -t cuda,cudnn,cublas,osrt,nvtx --cuda-memory-usage true --cudabacktrace all \ - --cuda-graph-trace $cuda_graph_trace \ - -e $envs,NSYS_NVTX_PROFILER_REGISTER_ONLY=0 \ - -o sam2_fp16_profile_${component}_${engine}_${cpu_or_gpu} \ - $python benchmark_sam2.py --model_type $model --engine $engine \ - --sam2_dir $sam2_dir --warm_up 1 --repeats 0 \ - --onnx_path ${onnx_dir}/${model}_${component}_fp16_gpu.onnx \ - --component $component \ - --use_gpu --dtype fp16 --enable_nvtx_profile - done + for component in image_encoder image_decoder; do + sudo "$install_dir/cuda${cuda_version}/bin/nsys" profile --capture-range=nvtx --nvtx-capture='one_run' \ + --gpu-metrics-devices $device_id --force-overwrite true \ + --sample process-tree --backtrace fp --stats true \ + -t cuda,cudnn,cublas,osrt,nvtx --cuda-memory-usage true --cudabacktrace all \ + --cuda-graph-trace "$cuda_graph_trace" \ + -e "$envs,NSYS_NVTX_PROFILER_REGISTER_ONLY=0" \ + -o "sam2_fp16_profile_${component}_${engine}_${cpu_or_gpu}" \ + $python benchmark_sam2.py --model_type "$model" --engine "$engine" \ + --sam2_dir "$sam2_dir" --warm_up 1 --repeats 0 \ + --onnx_path "${onnx_dir}/${model}_${component}_fp16_gpu.onnx" \ + --component "$component" \ + --use_gpu --dtype fp16 --enable_nvtx_profile done } -# Run profiling with PyTorch -run_torch_profile() { +run_ort_profile() { + export ORT_ENABLE_CUDNN_FLASH_ATTENTION=1 + rm -f onnxruntime_*.json for component in image_encoder image_decoder; do - $python benchmark_sam2.py --model_type $model --engine torch \ - --sam2_dir $sam2_dir --warm_up 1 --repeats 0 \ - --component $component \ - --use_gpu --dtype fp16 --enable_torch_profile + $python benchmark_sam2.py --model_type "$model" --engine ort \ + --sam2_dir "$sam2_dir" --warm_up 1 --repeats 0 \ + --onnx_path "${onnx_dir}/${model}_${component}_fp16_gpu.onnx" \ + --component "$component" \ + --use_gpu --dtype fp16 --enable_ort_profile + mv onnxruntime_profile*.json onnxruntime_$component.json done } -run_profilings() { - build_onnxruntime_gpu_for_profiling +# Run profiling with PyTorch +run_torch_profile() { + # Enable logging might could help get the code of compiled kernels. You can turn it off to reduce overhead. + export TORCH_LOGS="+inductor,+output_code" + export TORCHINDUCTOR_UNIQUE_KERNEL_NAMES=1 + component=image_encoder + $python benchmark_sam2.py --model_type "$model" --engine torch \ + --sam2_dir "$sam2_dir" --warm_up 1 --repeats 0 \ + --component "$component" \ + --torch_compile_mode max-autotune \ + --use_gpu --dtype fp16 --enable_torch_profile > "torch_${component}_compiled_code.txt" + + component=image_decoder + $python benchmark_sam2.py --model_type "$model" --engine torch \ + --sam2_dir "$sam2_dir" --warm_up 1 --repeats 0 \ + --component "$component" \ + --torch_compile_mode none \ + --use_gpu --dtype fp16 --enable_torch_profile +} +run_nvtx_profilings() { + build_onnxruntime_gpu_for_profiling rm -f *.nsys-rep *.sqlite - run_nvtx_profile + run_nvtx_profile ort + run_nvtx_profile torch +} +run_profilings() { + pip install nvtx cuda-python==${cuda_version}.0 + run_ort_profile run_torch_profile + + # NVTX profiling need to build onnxruntime-gpu from source so it is put as the last step. + run_nvtx_profilings } -profiling="${3:-false}" if [ "$profiling" = "true" ] && [ "$cpu_or_gpu" = "gpu" ]; then run_profilings fi diff --git a/onnxruntime/python/tools/transformers/models/sam2/convert_to_onnx.py b/onnxruntime/python/tools/transformers/models/sam2/convert_to_onnx.py index cacad717faf9c..3533a274b9972 100644 --- a/onnxruntime/python/tools/transformers/models/sam2/convert_to_onnx.py +++ b/onnxruntime/python/tools/transformers/models/sam2/convert_to_onnx.py @@ -113,6 +113,14 @@ def parse_arguments(): help="Optimize onnx models for GPU", ) + parser.add_argument( + "--dynamo", + required=False, + default=False, + action="store_true", + help="Use dynamo for exporting onnx model. Only image_encoder supports dynamo right now.", + ) + parser.add_argument( "--verbose", required=False, @@ -151,8 +159,10 @@ def main(): onnx_model_path = sam2_onnx_path(args.output_dir, args.model_type, component, args.multimask_output) if component == "image_encoder": if args.overwrite or not os.path.exists(onnx_model_path): - export_image_encoder_onnx(sam2_model, onnx_model_path, args.dynamic_batch_axes, args.verbose) - test_image_encoder_onnx(sam2_model, onnx_model_path, dynamic_batch_axes=False) + export_image_encoder_onnx( + sam2_model, onnx_model_path, args.dynamic_batch_axes, args.verbose, args.dynamo + ) + test_image_encoder_onnx(sam2_model, onnx_model_path, dynamic_batch_axes=args.dynamic_batch_axes) elif component == "mask_decoder": if args.overwrite or not os.path.exists(onnx_model_path): diff --git a/onnxruntime/python/tools/transformers/models/sam2/image_decoder.py b/onnxruntime/python/tools/transformers/models/sam2/image_decoder.py index 07ed150631f50..376e6ba7d802c 100644 --- a/onnxruntime/python/tools/transformers/models/sam2/image_decoder.py +++ b/onnxruntime/python/tools/transformers/models/sam2/image_decoder.py @@ -246,7 +246,7 @@ def test_decoder_onnx( import onnxruntime - ort_session = onnxruntime.InferenceSession(onnx_model_path, providers=onnxruntime.get_available_providers()) + ort_session = onnxruntime.InferenceSession(onnx_model_path, providers=["CPUExecutionProvider"]) model_inputs = ort_session.get_inputs() input_names = [model_inputs[i].name for i in range(len(model_inputs))] diff --git a/onnxruntime/python/tools/transformers/models/sam2/image_encoder.py b/onnxruntime/python/tools/transformers/models/sam2/image_encoder.py index c5ce339732063..79e9297788c36 100644 --- a/onnxruntime/python/tools/transformers/models/sam2/image_encoder.py +++ b/onnxruntime/python/tools/transformers/models/sam2/image_encoder.py @@ -90,6 +90,8 @@ def export_image_encoder_onnx( onnx_model_path: str, dynamic_batch_axes: bool = False, verbose: bool = False, + dynamo: bool = False, + clear_dynamo_metadata: bool = False, ): image = random_sam2_input_image() @@ -113,17 +115,65 @@ def export_image_encoder_onnx( if not verbose: warnings.filterwarnings("ignore", category=torch.jit.TracerWarning) warnings.filterwarnings("ignore", category=UserWarning) - torch.onnx.export( - sam2_encoder, - image, - onnx_model_path, - export_params=True, - opset_version=17, - do_constant_folding=True, - input_names=["image"], - output_names=["image_features_0", "image_features_1", "image_embeddings"], - dynamic_axes=dynamic_axes, - ) + + if not dynamo: + torch.onnx.export( + sam2_encoder, + image, + onnx_model_path, + export_params=True, + opset_version=17, + do_constant_folding=True, + input_names=["image"], + output_names=["image_features_0", "image_features_1", "image_embeddings"], + dynamic_axes=dynamic_axes, + ) + else: + torch._dynamo.config.capture_scalar_outputs = True + ep = torch.export.export( + sam2_encoder, + args=(image,), + strict=False, + dynamic_shapes=[ + {0: torch.export.Dim.AUTO}, + ], + ) + + onnx_program = torch.onnx.export( + ep, + (), + opset_version=17, + input_names=["image"], + output_names=["image_features_0", "image_features_1", "image_embeddings"], + dynamo=True, + ) + onnx_program.optimize() + onnx_program.save(onnx_model_path + ".dynamo.onnx", external_data=False) + import onnx + + from onnxruntime.transformers.dynamo_onnx_helper import DynamoOnnxHelper + + onnx_model = onnx.load_model(onnx_model_path + ".dynamo.onnx", load_external_data=True) + if dynamic_batch_axes: + # Fix labels of dynamic axes since they can't be specified during Dynamo export currently + onnx_model.graph.input[0].type.tensor_type.shape.dim[0].dim_param = "batch_size" + for i in range(3): + onnx_model.graph.output[i].type.tensor_type.shape.dim[0].dim_param = "batch_size" + + onnx_model_helper = DynamoOnnxHelper(onnx_model) + onnx_model_helper.convert_constants_to_initializers() + if clear_dynamo_metadata: + onnx_model_helper.clear_metadata() + + import os + + if os.path.exists(onnx_model_path): + os.remove(onnx_model_path) + if os.path.exists(onnx_model_path + ".data"): + os.remove(onnx_model_path + ".data") + onnx_model_helper.model.save_model_to_file( + onnx_model_path, use_external_data_format=True, all_tensors_to_one_file=True, convert_attribute=True + ) print("encoder onnx model saved to", onnx_model_path) @@ -133,7 +183,7 @@ def test_image_encoder_onnx( onnx_model_path: str, dynamic_batch_axes=False, ): - ort_session = onnxruntime.InferenceSession(onnx_model_path, providers=onnxruntime.get_available_providers()) + ort_session = onnxruntime.InferenceSession(onnx_model_path, providers=["CPUExecutionProvider"]) model_inputs = ort_session.get_inputs() input_names = [model_inputs[i].name for i in range(len(model_inputs))] diff --git a/onnxruntime/python/tools/transformers/models/sam2/mask_decoder.py b/onnxruntime/python/tools/transformers/models/sam2/mask_decoder.py index 56473c002d4ae..fa83e2f666d06 100644 --- a/onnxruntime/python/tools/transformers/models/sam2/mask_decoder.py +++ b/onnxruntime/python/tools/transformers/models/sam2/mask_decoder.py @@ -177,7 +177,7 @@ def test_mask_decoder_onnx( import onnxruntime - ort_session = onnxruntime.InferenceSession(onnx_model_path, providers=onnxruntime.get_available_providers()) + ort_session = onnxruntime.InferenceSession(onnx_model_path, providers=["CPUExecutionProvider"]) model_inputs = ort_session.get_inputs() input_names = [model_inputs[i].name for i in range(len(model_inputs))] diff --git a/onnxruntime/python/tools/transformers/models/sam2/prompt_encoder.py b/onnxruntime/python/tools/transformers/models/sam2/prompt_encoder.py index 883c51858346c..f25e6ff23324b 100644 --- a/onnxruntime/python/tools/transformers/models/sam2/prompt_encoder.py +++ b/onnxruntime/python/tools/transformers/models/sam2/prompt_encoder.py @@ -146,7 +146,7 @@ def test_prompt_encoder_onnx( import onnxruntime - ort_session = onnxruntime.InferenceSession(onnx_model_path, providers=onnxruntime.get_available_providers()) + ort_session = onnxruntime.InferenceSession(onnx_model_path, providers=["CPUExecutionProvider"]) model_inputs = ort_session.get_inputs() input_names = [model_inputs[i].name for i in range(len(model_inputs))] diff --git a/onnxruntime/python/tools/transformers/models/stable_diffusion/README.md b/onnxruntime/python/tools/transformers/models/stable_diffusion/README.md index dc83f4dc220f0..2506ffe8a3f50 100644 --- a/onnxruntime/python/tools/transformers/models/stable_diffusion/README.md +++ b/onnxruntime/python/tools/transformers/models/stable_diffusion/README.md @@ -143,29 +143,11 @@ conda activate py310 ### Setup Environment (CUDA) without docker -First, we need install CUDA 11.8 or 12.x, [cuDNN](https://docs.nvidia.com/deeplearning/cudnn/install-guide/index.html), and [TensorRT](https://docs.nvidia.com/deeplearning/tensorrt/install-guide/index.html) in the machine. +First, we need install CUDA 12.x, [cuDNN](https://docs.nvidia.com/deeplearning/cudnn/install-guide/index.html), and [TensorRT](https://docs.nvidia.com/deeplearning/tensorrt/install-guide/index.html) in the machine. The verison of CuDNN can be found in https://onnxruntime.ai/docs/execution-providers/CUDA-ExecutionProvider.html#requirements. The version of TensorRT can be found in https://onnxruntime.ai/docs/execution-providers/TensorRT-ExecutionProvider.html#requirements. -#### CUDA 11.8: - -In the Conda environment, install PyTorch 2.1 up to 2.3.1, and other required packages like the following: -``` -pip install torch>=2.1,<2.4 --index-url https://download.pytorch.org/whl/cu118 -pip install --upgrade polygraphy onnx-graphsurgeon --extra-index-url https://pypi.ngc.nvidia.com -pip install -r requirements/cuda11/requirements.txt -``` - -For Windows, install nvtx like the following: -``` -conda install -c conda-forge nvtx -``` - -We cannot directly `pip install tensorrt` for CUDA 11. Follow https://github.com/NVIDIA/TensorRT/issues/2773 to install TensorRT for CUDA 11 in Linux. - -For Windows, pip install the tensorrt wheel in the downloaded TensorRT zip file instead. Like `pip install tensorrt-8.6.1.6.windows10.x86_64.cuda-11.8\tensorrt-8.6.1.6\python\tensorrt-8.6.1-cp310-none-win_amd64.whl`. - #### CUDA 12.*: The official package of onnxruntime-gpu 1.19.x is built for CUDA 12.x. You can install it and other python packages like the following: ``` diff --git a/onnxruntime/python/tools/transformers/models/t5/convert_to_onnx.py b/onnxruntime/python/tools/transformers/models/t5/convert_to_onnx.py index adf5206be8353..dd519e36cfa88 100755 --- a/onnxruntime/python/tools/transformers/models/t5/convert_to_onnx.py +++ b/onnxruntime/python/tools/transformers/models/t5/convert_to_onnx.py @@ -10,8 +10,15 @@ import os import torch -from benchmark_helper import Precision, create_onnxruntime_session, prepare_environment, setup_logger +from benchmark_helper import ( + Precision, + create_onnxruntime_session, + prepare_environment, + setup_logger, +) +from onnx.shape_inference import infer_shapes_path from t5_helper import PRETRAINED_MT5_MODELS, PRETRAINED_T5_MODELS, T5Helper +from transformers import MT5Config, T5Config logger = logging.getLogger("") @@ -70,9 +77,9 @@ def parse_arguments(): "-p", "--precision", required=False, - type=Precision, - default=Precision.FLOAT32, - choices=[Precision.FLOAT32, Precision.FLOAT16], + type=str, + default=Precision.FLOAT32.value, + choices=[Precision.FLOAT32.value, Precision.FLOAT16.value], help="Precision of model to run. fp32 for full precision, fp16 for half precision", ) @@ -104,17 +111,17 @@ def parse_arguments(): "--disable_auto_mixed_precision", required=False, action="store_true", - help="use pure fp16 instead of mixed precision", + help="do not use auto mixed precision conversion", ) parser.set_defaults(disable_auto_mixed_precision=False) parser.add_argument( - "--separate_encoder_and_decoder_init", + "--force_fp16_io", required=False, action="store_true", - help="Do not merge encode and decoder init. Output 3 instead of 2 onnx models.", + help="Force to convert all float inputs and outputs to fp16 when precision is fp16.", ) - parser.set_defaults(separate_encoder_and_decoder_init=False) + parser.set_defaults(force_fp16_io=False) parser.add_argument( "--use_int64_inputs", @@ -131,34 +138,52 @@ def parse_arguments(): help="filepath to load pre-trained model with custom state dictionary (e.g. pytorch_model.bin)", ) + parser.add_argument( + "--encoder_decoder_init", + required=False, + action="store_true", + help="Combine encoder and decoder kv cache initialization into one model. It is legacy format that will be deprecated.", + ) + parser.set_defaults(encoder_decoder_init=False) + args = parser.parse_args() return args def export_onnx_models( - model_name_or_path, - cache_dir, - output_dir, - use_gpu, - use_external_data_format, - optimize_onnx, - precision, - verbose, + model_name_or_path: str, + cache_dir: str, + output_dir: str, + use_gpu: bool = False, + use_external_data_format: bool = False, + optimize_onnx: bool = False, + precision: str = Precision.FLOAT32.value, + verbose: bool = False, use_decoder_start_token: bool = False, - merge_encoder_and_decoder_init: bool = True, overwrite: bool = False, disable_auto_mixed_precision: bool = False, use_int32_inputs: bool = True, model_type: str = "t5", state_dict_path: str = "", + encoder_decoder_init: bool = False, + force_fp16_io: bool = False, + shape_infer_before_optimization: bool = False, ): + assert precision in [Precision.FLOAT32.value, Precision.FLOAT16.value], ( + f"Invalid precision: {precision}. Use 'fp32' or 'fp16'." + ) device = torch.device("cuda:0" if use_gpu else "cpu") models = T5Helper.load_model( - model_name_or_path, cache_dir, device, merge_encoder_and_decoder_init, model_type, state_dict_path + model_name_or_path, + cache_dir, + device, + model_type, + state_dict_path, + encoder_decoder_init=encoder_decoder_init, ) - config = models["decoder"].config + config: T5Config | MT5Config = models["decoder"].config if (not use_external_data_format) and (config.num_layers > 24): logger.info("Try use_external_data_format when model size > 2GB") @@ -191,8 +216,20 @@ def export_onnx_models( else: logger.info(f"Skip exporting: existed ONNX model {onnx_path}") - # Optimize ONNX graph. Note that we have not implemented graph optimization for T5 yet. - if optimize_onnx or precision != Precision.FLOAT32: + # Optimize ONNX graph. + # The precision shall be compared with string value. It is because the Precision enum loaded from local file + # (like by transformers test in CI pipeline) are not same as Precision enum from package. + if optimize_onnx or precision != Precision.FLOAT32.value: + onnx_shape_path = None + if shape_infer_before_optimization: + onnx_shape_path = T5Helper.get_onnx_path( + output_dir, + model_name_or_path, + suffix=filename_suffix + "_shape", + new_folder=False, + ) + infer_shapes_path(onnx_path, onnx_shape_path) + output_path = T5Helper.get_onnx_path( output_dir, model_name_or_path, @@ -203,30 +240,35 @@ def export_onnx_models( if overwrite or not os.path.exists(output_path): logger.info(f"Optimizing model to {output_path}") T5Helper.optimize_onnx( - onnx_path, + onnx_shape_path or onnx_path, output_path, - precision == Precision.FLOAT16, + precision == Precision.FLOAT16.value, config.num_heads, config.hidden_size, use_external_data_format, auto_mixed_precision=not disable_auto_mixed_precision, use_gpu=use_gpu, + force_fp16_io=force_fp16_io, ) else: - logger.info(f"Skip optimizing: existed ONNX model {onnx_path}") + logger.info(f"Skip optimizing: existed ONNX model {output_path}") else: output_path = onnx_path ort_session = create_onnxruntime_session( output_path, use_gpu=use_gpu, - provider=["CUDAExecutionProvider", "CPUExecutionProvider"] if use_gpu else ["CPUExecutionProvider"], + verbose=verbose, ) + if ort_session is None: + break with torch.no_grad(): max_diff = T5Helper.verify_onnx(model, ort_session, device, use_int32_inputs) logger.info(f"PyTorch and OnnxRuntime results max difference = {max_diff}") - if max_diff > 1e-4: + + # The threshold cannot apply to fp16 model, which need a larger threshold. + if precision == Precision.FLOAT32.value and max_diff > 1e-4: logger.warning("PyTorch and OnnxRuntime results are NOT close") output_paths.append(output_path) @@ -245,15 +287,12 @@ def main(): output_dir = args.output if not args.output.endswith(".onnx") else os.path.dirname(args.output) prepare_environment(cache_dir, output_dir, args.use_gpu) - if args.precision != Precision.FLOAT32: + if args.precision != Precision.FLOAT32.value: assert args.optimize_onnx, "fp16/int8 requires --optimize_onnx" - if args.precision == Precision.FLOAT16: + if args.precision == Precision.FLOAT16.value: assert args.use_gpu, "fp16 requires --use_gpu" - if args.optimize_onnx: - logger.warning("Graph optimization for T5 is not implemented yet.") - output_paths = export_onnx_models( args.model_name_or_path, cache_dir, @@ -264,11 +303,12 @@ def main(): args.precision, args.verbose, args.use_decoder_start_token, - not args.separate_encoder_and_decoder_init, args.overwrite, args.disable_auto_mixed_precision, not args.use_int64_inputs, args.model_type, + encoder_decoder_init=args.encoder_decoder_init, + force_fp16_io=args.force_fp16_io, ) logger.info(f"Done! Outputs: {output_paths}") diff --git a/onnxruntime/python/tools/transformers/models/t5/t5_encoder.py b/onnxruntime/python/tools/transformers/models/t5/t5_encoder.py index c6b0f7ee3adc2..df3a416f2947c 100644 --- a/onnxruntime/python/tools/transformers/models/t5/t5_encoder.py +++ b/onnxruntime/python/tools/transformers/models/t5/t5_encoder.py @@ -1,24 +1,14 @@ # ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# ------------------------------------------------------------------------- import logging -import os import random -import tempfile -from pathlib import Path -import numpy -import onnx import torch -from onnx_model import OnnxModel -from torch_onnx_export_helper import torch_onnx_export from transformers import MT5Config, T5Config -from onnxruntime import InferenceSession - logger = logging.getLogger(__name__) @@ -41,7 +31,11 @@ def __init__(self, input_ids, attention_mask): @staticmethod def create_dummy( - batch_size: int, sequence_length: int, vocab_size: int, device: torch.device, use_int32_inputs: bool = False + batch_size: int, + sequence_length: int, + vocab_size: int, + device: torch.device, + use_int32_inputs: bool = False, ): # -> T5EncoderInputs """Create dummy inputs for T5 encoder. @@ -74,97 +68,3 @@ def create_dummy( def to_list(self) -> list: input_list = [v for v in [self.input_ids, self.attention_mask] if v is not None] return input_list - - -class T5EncoderHelper: - @staticmethod - def export_onnx( - encoder: T5Encoder, - device: torch.device, - onnx_model_path: str, - verbose: bool = True, - use_external_data_format: bool = False, - use_int32_inputs: bool = False, - ): - """Export encoder to ONNX - - Args: - encoder (T5Encoder): encoder object - device (torch.device): device of encoder object - onnx_model_path (str): onnx path - verbose (bool, optional): print verbose information. Defaults to True. - use_external_data_format (bool, optional): use external data format or not. Defaults to False. - """ - config = encoder.config - encoder_inputs = T5EncoderInputs.create_dummy( - batch_size=2, - sequence_length=4, - vocab_size=config.vocab_size, - device=device, - use_int32_inputs=use_int32_inputs, - ) - - Path(onnx_model_path).parent.mkdir(parents=True, exist_ok=True) - - with tempfile.TemporaryDirectory() as tmp_dir_name: - temp_onnx_model_path = os.path.join(tmp_dir_name, "encoder.onnx") - Path(temp_onnx_model_path).parent.mkdir(parents=True, exist_ok=True) - torch_onnx_export( - encoder, - args=tuple(encoder_inputs.to_list()), - f=temp_onnx_model_path if use_external_data_format else onnx_model_path, - export_params=True, - input_names=["input_ids", "attention_mask"], - output_names=["hidden_states"], - dynamic_axes={ - "input_ids": {0: "batch_size", 1: "sequence_length"}, - "attention_mask": {0: "batch_size", 1: "sequence_length"}, - "hidden_states": {0: "batch_size", 1: "sequence_length"}, - }, - opset_version=12, - do_constant_folding=True, - use_external_data_format=use_external_data_format, - verbose=verbose, - ) - - if use_external_data_format: - model = onnx.load_model(temp_onnx_model_path, load_external_data=True) - OnnxModel.save( - model, - onnx_model_path, - save_as_external_data=True, - all_tensors_to_one_file=True, - ) - - @staticmethod - def onnxruntime_inference(ort_session, inputs: T5EncoderInputs): - """Run inference of ONNX model.""" - ort_inputs = { - "input_ids": numpy.ascontiguousarray(inputs.input_ids.cpu().numpy()), - "attention_mask": numpy.ascontiguousarray(inputs.attention_mask.cpu().numpy()), - } - - return ort_session.run(None, ort_inputs) - - @staticmethod - def verify_onnx( - model: T5Encoder, ort_session: InferenceSession, device: torch.device, use_int32_inputs: bool = False - ): - """Compare the result from PyTorch and OnnxRuntime to verify the ONNX model is good.""" - inputs = T5EncoderInputs.create_dummy( - batch_size=4, - sequence_length=11, - vocab_size=model.config.vocab_size, - device=device, - use_int32_inputs=use_int32_inputs, - ) - input_list = inputs.to_list() - torch_outputs = model(*input_list) - - ort_outputs = T5EncoderHelper.onnxruntime_inference(ort_session, inputs) - - max_diff = numpy.amax(numpy.abs(torch_outputs.cpu().numpy() - ort_outputs[0])) - - logger.info(f"max_diff={max_diff}") - - return max_diff diff --git a/onnxruntime/python/tools/transformers/models/t5/t5_encoder_decoder_init.py b/onnxruntime/python/tools/transformers/models/t5/t5_encoder_decoder_init.py index c76d7aabdf11a..98df18eab6064 100644 --- a/onnxruntime/python/tools/transformers/models/t5/t5_encoder_decoder_init.py +++ b/onnxruntime/python/tools/transformers/models/t5/t5_encoder_decoder_init.py @@ -1,8 +1,7 @@ # ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# ------------------------------------------------------------------------- import logging import os @@ -31,33 +30,40 @@ def __init__( self, encoder: torch.nn.Module, decoder: torch.nn.Module, - lm_head: torch.nn.Module, + lm_head: torch.nn.Linear, config: T5Config | MT5Config, decoder_start_token_id: int | None = None, + output_cross_only: bool = False, ): super().__init__() - self.config = config + self.config: T5Config | MT5Config = config self.t5_encoder = T5Encoder(encoder, config) self.t5_decoder_init = T5DecoderInit(decoder, lm_head, config, decoder_start_token_id) + self.output_cross_only = output_cross_only def forward( self, encoder_input_ids: torch.Tensor, encoder_attention_mask: torch.Tensor, - decoder_input_ids: torch.Tensor = None, + decoder_input_ids: torch.Tensor | None = None, ): encoder_hidden_states: torch.FloatTensor = self.t5_encoder(encoder_input_ids, encoder_attention_mask) + lm_logits, past_self, past_cross = self.t5_decoder_init( decoder_input_ids, encoder_attention_mask, encoder_hidden_states ) - return lm_logits, encoder_hidden_states, past_self, past_cross + + if self.output_cross_only: + return past_cross + else: + return lm_logits, encoder_hidden_states, past_self, past_cross class T5EncoderDecoderInitInputs: def __init__(self, encoder_input_ids, encoder_attention_mask, decoder_input_ids=None): self.encoder_input_ids: torch.LongTensor = encoder_input_ids self.encoder_attention_mask: torch.LongTensor = encoder_attention_mask - self.decoder_input_ids: torch.LongTensor = decoder_input_ids + self.decoder_input_ids: torch.LongTensor | None = decoder_input_ids @staticmethod def create_dummy( @@ -108,9 +114,14 @@ def export_onnx( onnx_model_path (str): onnx path verbose (bool, optional): print verbose information. Defaults to True. use_external_data_format (bool, optional): use external data format or not. Defaults to False. + use_int32_inputs (bool, optional): use int32 instead of int64 for integer inputs. Defaults to False. """ assert isinstance(model, T5EncoderDecoderInit) + # Do not exclude decoder in torch onnx export so that cross can show up. + output_cross_only = model.output_cross_only + model.output_cross_only = False + inputs = T5EncoderDecoderInitInputs.create_dummy( model.config, batch_size=2, @@ -139,7 +150,7 @@ def export_onnx( input_names = ["encoder_input_ids", "encoder_attention_mask"] - # ONNX exporter might mark dimension like 'Transposepresent_value_self_1_dim_2' in shape inference. + # ONNX exporter might mark dimension like 'present_value_self_1_dim_2' in shape inference. # We use a workaround here: first use dim_param "1" for sequence_length, and later change to dim_value. sequence_length = "1" num_heads = str(model.config.num_heads) @@ -201,9 +212,12 @@ def export_onnx( verbose=verbose, ) + # Restore output_cross_only setting. + model.output_cross_only = output_cross_only + # Workaround as mentioned earlier: change numeric dim_param to dim_value - model = onnx.load(temp_onnx_model_path) - for tensor in model.graph.output: + exported_model: onnx.ModelProto = onnx.load(temp_onnx_model_path) + for tensor in exported_model.graph.output: for dim_proto in tensor.type.tensor_type.shape.dim: if dim_proto.HasField("dim_param") and dim_proto.dim_param in [ sequence_length, @@ -215,8 +229,50 @@ def export_onnx( dim_proto.Clear() dim_proto.dim_value = dim_value + if output_cross_only: + # Rewrite onnx graph to only keep present_[key|value]_cross_* outputs. + onnx_model = OnnxModel(exported_model) + output_name_to_node = onnx_model.output_name_to_node() + + for output in exported_model.graph.output: + if "cross" in output.name: + assert output.name in output_name_to_node + + transpose_node = output_name_to_node[output.name] + assert transpose_node and transpose_node.op_type == "Transpose" + + permutation = OnnxModel.get_node_attribute(transpose_node, "perm") + assert isinstance(permutation, list) + assert permutation == [0, 2, 1, 3] + + matched_nodes = onnx_model.match_parent_path( + transpose_node, + ["Reshape", "MatMul"], + [0, 0], + output_name_to_node, + ) + assert matched_nodes is not None + + reshape_node, matmul_node = matched_nodes + assert "encoder_hidden_states" in matmul_node.input + + if not onnx_model.get_initializer("cross_reshape_shape"): + shape_tensor = onnx.helper.make_tensor( + name="cross_reshape_shape", + data_type=onnx.TensorProto.INT64, + dims=[4], + vals=[0, 0, int(num_heads), int(head_size)], + raw=False, + ) + onnx_model.add_initializer(shape_tensor) + + reshape_node.input[1] = "cross_reshape_shape" + + cross_outputs = [output.name for output in exported_model.graph.output if "cross" in output.name] + onnx_model.prune_graph(cross_outputs, allow_remove_graph_inputs=True) + OnnxModel.save( - model, + exported_model, onnx_model_path, save_as_external_data=use_external_data_format, all_tensors_to_one_file=True, @@ -269,27 +325,34 @@ def verify_onnx( num_decoder_layers = model.config.num_decoder_layers - assert torch_outputs[0].cpu().numpy().shape == ort_outputs[0].shape - max_diff = numpy.amax(numpy.abs(torch_outputs[0].cpu().numpy() - ort_outputs[0])) - logger.debug(f"logits max_diff={max_diff}") - max_diff_all = max_diff - - assert torch_outputs[1].cpu().numpy().shape == ort_outputs[1].shape - max_diff = numpy.amax(numpy.abs(torch_outputs[1].cpu().numpy() - ort_outputs[1])) - logger.debug(f"encoder_hidden_states max_diff={max_diff}") - max_diff_all = max(max_diff_all, max_diff) - - for i in range(2 * num_decoder_layers): - max_diff = numpy.amax(numpy.abs(torch_outputs[2][i].cpu().numpy() - ort_outputs[2 + i])) - logger.debug(f"self attention past state {i} max_diff={max_diff}") - - for i in range(2 * num_decoder_layers): - max_diff = numpy.amax( - numpy.abs(torch_outputs[3][i].cpu().numpy() - ort_outputs[2 + 2 * num_decoder_layers + i]) - ) - logger.debug(f"cross attention past state {i} max_diff={max_diff}") + if not model.output_cross_only: + assert torch_outputs[0].cpu().numpy().shape == ort_outputs[0].shape + max_diff = numpy.amax(numpy.abs(torch_outputs[0].cpu().numpy() - ort_outputs[0])) + logger.debug(f"logits max_diff={max_diff}") + max_diff_all = max_diff + + assert torch_outputs[1].cpu().numpy().shape == ort_outputs[1].shape + max_diff = numpy.amax(numpy.abs(torch_outputs[1].cpu().numpy() - ort_outputs[1])) + logger.debug(f"encoder_hidden_states max_diff={max_diff}") max_diff_all = max(max_diff_all, max_diff) + for i in range(2 * num_decoder_layers): + max_diff = numpy.amax(numpy.abs(torch_outputs[2][i].cpu().numpy() - ort_outputs[2 + i])) + logger.debug(f"self attention past state {i} max_diff={max_diff}") + + for i in range(2 * num_decoder_layers): + max_diff = numpy.amax( + numpy.abs(torch_outputs[3][i].cpu().numpy() - ort_outputs[2 + 2 * num_decoder_layers + i]) + ) + logger.debug(f"cross attention past state {i} max_diff={max_diff}") + max_diff_all = max(max_diff_all, max_diff) + else: + max_diff_all = -float("inf") + for i in range(2 * num_decoder_layers): + max_diff = numpy.amax(numpy.abs(torch_outputs[i].cpu().numpy() - ort_outputs[i])) + logger.debug(f"cross attention past state {i} max_diff={max_diff}") + max_diff_all = max(max_diff_all, max_diff) + test_cases_max_diff.append(max_diff_all) logger.info( f"batch_size={batch_size} encode_sequence_length={encode_sequence_length}, max_diff={max_diff_all}" diff --git a/onnxruntime/python/tools/transformers/models/t5/t5_helper.py b/onnxruntime/python/tools/transformers/models/t5/t5_helper.py index d3f25e979887d..7552008f920e0 100755 --- a/onnxruntime/python/tools/transformers/models/t5/t5_helper.py +++ b/onnxruntime/python/tools/transformers/models/t5/t5_helper.py @@ -1,8 +1,7 @@ # ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# ------------------------------------------------------------------------- import logging import os @@ -12,8 +11,7 @@ from float16 import float_to_float16_max_diff from onnx_model import OnnxModel from optimizer import optimize_model -from t5_decoder import T5Decoder, T5DecoderHelper, T5DecoderInit -from t5_encoder import T5Encoder, T5EncoderHelper +from t5_decoder import T5Decoder, T5DecoderHelper from t5_encoder_decoder_init import T5EncoderDecoderInit, T5EncoderDecoderInitHelper from transformers import MT5ForConditionalGeneration, T5ForConditionalGeneration @@ -22,7 +20,13 @@ logger = logging.getLogger(__name__) PRETRAINED_T5_MODELS = ["t5-small", "t5-base", "t5-large", "t5-3b", "t5-11b"] -PRETRAINED_MT5_MODELS = ["google/mt5-small", "google/mt5-base", "google/mt5-large", "google/mt5-xl", "google/mt5-xxl"] +PRETRAINED_MT5_MODELS = [ + "google/mt5-small", + "google/mt5-base", + "google/mt5-large", + "google/mt5-xl", + "google/mt5-xxl", +] class T5Helper: @@ -60,18 +64,19 @@ def load_model( model_name_or_path: str, cache_dir: str, device: torch.device, - merge_encoder_and_decoder_init: bool = True, model_type: str = "t5", state_dict_path: str = "", - ) -> dict[str, torch.nn.Module]: + encoder_decoder_init: bool = False, + ) -> dict[str, T5EncoderDecoderInit | T5Decoder]: """Load model given a pretrained name or path, then build models for ONNX conversion. Args: model_name_or_path (str): pretrained model name or path cache_dir (str): cache directory device (torch.device): device to run the model - merge_encoder_and_decoder_init (bool, optional): Whether merge encoder and decoder initialization into one ONNX model. Defaults to True. - is_mt5 (bool, optional): whether the model is MT5 instead of T5 + model_type (str, optional): model type "t5" or "mt5" + state_dict_path(str, optional): state dictionary path + encoder_decoder_init (bool, optional): combine encoder and decoder kv cache initialization into one model. Returns: Dict[str, torch.nn.Module]: mapping from name to modules for ONNX conversion. """ @@ -88,29 +93,21 @@ def load_model( decoder = T5Decoder(model.decoder, model.lm_head, model.config) decoder.eval().to(device) - if merge_encoder_and_decoder_init: - encoder_decoder_init = T5EncoderDecoderInit( - model.encoder, - model.decoder, - model.lm_head, - model.config, - decoder_start_token_id=None, - ) - return {"encoder_decoder_init": encoder_decoder_init, "decoder": decoder} - else: - encoder = T5Encoder(model.encoder, model.config) - encoder.eval().to(device) - decoder_init = T5DecoderInit(model.decoder, model.lm_head, model.config) - decoder_init.eval().to(device) - return { - "encoder": encoder, - "decoder": decoder, - "decoder_init": decoder_init, - } + encoder = T5EncoderDecoderInit( + model.encoder, + model.decoder, + model.lm_head, + model.config, + decoder_start_token_id=None, + output_cross_only=not encoder_decoder_init, + ) + + encoder_name = "encoder_decoder_init" if encoder_decoder_init else "encoder" + return {encoder_name: encoder, "decoder": decoder} @staticmethod def export_onnx( - model: T5Encoder | T5Decoder | T5DecoderInit | T5EncoderDecoderInit, + model: T5Decoder | T5EncoderDecoderInit, device: torch.device, onnx_model_path: str, verbose: bool = True, @@ -118,16 +115,7 @@ def export_onnx( use_decoder_input_ids: bool = True, use_int32_inputs: bool = False, ): - if isinstance(model, T5Encoder): - T5EncoderHelper.export_onnx( - model, - device, - onnx_model_path, - verbose, - use_external_data_format, - use_int32_inputs, - ) - elif isinstance(model, T5EncoderDecoderInit): + if isinstance(model, T5EncoderDecoderInit): T5EncoderDecoderInitHelper.export_onnx( model, device, @@ -150,21 +138,28 @@ def export_onnx( @staticmethod def auto_mixed_precision( onnx_model: OnnxModel, - op_block_list: list[str] = [ # noqa: B006 - "SimplifiedLayerNormalization", - "SkipSimplifiedLayerNormalization", - "Relu", - "Add", - ], + op_block_list: list[str] | None = None, + force_fp16_logits: bool = False, + use_symbolic_shape_infer: bool = True, ): """Convert model to mixed precision. It detects whether original model has fp16 precision weights, and set parameters for float16 conversion automatically. Args: onnx_model (OnnxModel): optimized ONNX model - op_block_list (List[str], optional): . Defaults to ["SimplifiedLayerNormalization", "SkipSimplifiedLayerNormalization", "Relu", "Add"] + op_block_list (List[str], optional): operators need to run in fp32. + force_fp16_logits (bool, optional): force logits and last MatMul node to be in float16. Defaults to False. + use_symbolic_shape_infer (bool, optional): use symbolic shape inference to convert float to float16. Defaults to True. Returns: parameters(dict): a dictionary of parameters used in float16 conversion """ + if op_block_list is None: + op_block_list = [ + "SimplifiedLayerNormalization", + "SkipSimplifiedLayerNormalization", + "Relu", + "Add", + ] + op_full_set = {node.op_type for node in onnx_model.nodes()} fp32_op_set = set(op_block_list) fp16_op_set = op_full_set.difference(fp32_op_set) @@ -198,11 +193,38 @@ def auto_mixed_precision( keep_io_types = [] node_block_list = [] - if (not is_weight_fp16_precision) and (last_matmul_node is not None): + if (not is_weight_fp16_precision) and (last_matmul_node is not None) and not force_fp16_logits: # When original weight is float32 precision, keep logits and last MatMul in float32 could get better precision. keep_io_types = [logits_output_name] node_block_list = [last_matmul_node.name] + if "Add" not in op_block_list: + input_name_to_nodes = onnx_model.input_name_to_nodes() + fp32_add = 0 + changed = True + add_nodes = onnx_model.get_nodes_by_op_type("Add") + while changed: + changed = False + for node in add_nodes: + if node.name not in node_block_list: + parents = onnx_model.get_parents(node, output_name_to_node) + children = onnx_model.get_children(node, input_name_to_nodes) + blocked_children = [ + child for child in children if child.op_type in op_block_list or child in node_block_list + ] + blocked_parents = [ + parent for parent in parents if parent.op_type in op_block_list or parent in node_block_list + ] + # If any child or parent is in fp32, we place the Add node to fp32. + if (len(blocked_children) + len(blocked_parents)) > 0: + node_block_list.append(node.name) + fp32_add += 1 + changed = True + fp16_add = len(add_nodes) - fp32_add + logger.info(f"node counter of Add operator: fp32={fp32_add} fp16={fp16_add}") + + logger.info(f"node_block_list: {node_block_list}") + parameters = { "keep_io_types": keep_io_types, "op_block_list": op_block_list, @@ -211,7 +233,18 @@ def auto_mixed_precision( } logger.info(f"auto_mixed_precision parameters: {parameters}") - onnx_model.convert_float_to_float16(use_symbolic_shape_infer=True, **parameters) + if use_symbolic_shape_infer: + onnx_model.convert_float_to_float16(use_symbolic_shape_infer=True, **parameters) + else: + # Workaround when symbolic shape inference fails. + # Need enable shape_infer_before_optimization in convert_to_onnx.py as well. + from float16 import convert_float_to_float16 + + convert_float_to_float16( + onnx_model.model, + disable_shape_infer=True, + **parameters, + ) return parameters @@ -225,6 +258,7 @@ def optimize_onnx( use_external_data_format: bool = False, auto_mixed_precision: bool = True, use_gpu: bool = False, + force_fp16_io: bool = False, ): """Optimize ONNX model with an option to convert it to use mixed precision.""" @@ -233,38 +267,35 @@ def optimize_onnx( optimization_options = None if is_float16: optimization_options = FusionOptions("t5") - optimization_options.enable_skip_layer_norm = False + # SkipLayerNormalization is faster but might bring accuracy drop since it uses fp16 accumulation. + optimization_options.enable_skip_layer_norm = not auto_mixed_precision m = optimize_model( onnx_model_path, model_type="t5", num_heads=num_attention_heads, hidden_size=hidden_size, - opt_level=2 if not use_external_data_format else 0, + opt_level=0, optimization_options=optimization_options, - use_gpu=False, - only_onnxruntime=not use_gpu, + use_gpu=use_gpu, ) if is_float16: if auto_mixed_precision: - T5Helper.auto_mixed_precision(m) + T5Helper.auto_mixed_precision(m, force_fp16_logits=force_fp16_io) else: - m.convert_model_float32_to_float16(cast_input_output=False) + m.convert_model_float32_to_float16(cast_input_output=force_fp16_io) m.save_model_to_file(optimized_model_path, use_external_data_format, all_tensors_to_one_file=True) @staticmethod def verify_onnx( - model: T5Encoder | T5Decoder | T5DecoderInit | T5EncoderDecoderInit, + model: T5Decoder | T5EncoderDecoderInit, ort_session: InferenceSession, device: torch.device, use_int32_inputs: bool, ): """Compare the result from PyTorch and OnnxRuntime to verify the ONNX model is good.""" - if isinstance(model, T5Encoder): - return T5EncoderHelper.verify_onnx(model, ort_session, device, use_int32_inputs) - if isinstance(model, T5EncoderDecoderInit): return T5EncoderDecoderInitHelper.verify_onnx(model, ort_session, device, use_int32_inputs) diff --git a/onnxruntime/python/tools/transformers/models/whisper/README.md b/onnxruntime/python/tools/transformers/models/whisper/README.md index 6e3385a1a9cc6..598eeea8d2e49 100644 --- a/onnxruntime/python/tools/transformers/models/whisper/README.md +++ b/onnxruntime/python/tools/transformers/models/whisper/README.md @@ -19,9 +19,65 @@ In addition to the above packages, you will need to install `ffmpeg` on your mac **FFMPEG includes numerous codecs, many of which are likely not used by your product/service. Microsoft engineering teams using FFMPEG must build FFMPEG to remove all the unneeded and unused codecs. Including codecs in your product/service, even if not used, can create patent risk for Microsoft. You are responsible for building FFMPEG in a way that follows this codec guidance.** +## Exporting Whisper + +It is recommended to export Whisper for ONNX Runtime GenAI as you will get much more granular control over the generation loop and you can produce word-level timestamps. The alternative option is to export Whisper with the beam search op in the ONNX model, which does not provide these extra benefits and may have additional limitations. + +To see all available options: +``` +# From source: +$ python3 -m models.whisper.convert_to_onnx --help + +# From wheel: +$ python3 -m onnxruntime.transformers.models.whisper.convert_to_onnx --help +``` + +## Exporting Whisper for [ONNX Runtime GenAI](https://github.com/microsoft/onnxruntime-genai) + +To export Whisper for ONNX Runtime GenAI, you can use the `convert_to_onnx.py` script. + +``` +# From source +$ git clone https://github.com/microsoft/onnxruntime +$ cd onnxruntime/onnxruntime/python/tools/transformers/ +$ python3 -m models.whisper.convert_to_onnx -m openai/whisper-large-v3-turbo --output whisper-turbo --use_external_data_format --no_beam_search_op --output_cross_qk + +# From wheel +$ python3 -m onnxruntime.transformers.models.whisper.convert_to_onnx -m openai/whisper-large-v3-turbo --output whisper-turbo --use_external_data_format --no_beam_search_op --output_cross_qk +``` + +Here are some additional examples for exporting Whisper for ONNX Runtime GenAI. + +Export + Optimize for FP32 CPU +``` +# From source: +$ python3 -m models.whisper.convert_to_onnx -m openai/whisper-large-v3-turbo --output whisper-turbo --precision fp32 --provider cpu --use_external_data_format --optimize_onnx --no_beam_search_op --output_cross_qk + +# From wheel: +$ python3 -m onnxruntime.transformers.models.whisper.convert_to_onnx -m openai/whisper-large-v3-turbo --output whisper-turbo --precision fp32 --provider cpu --use_external_data_format --optimize_onnx --no_beam_search_op --output_cross_qk +``` + +Export + Optimize for FP32 CUDA +``` +# From source: +$ python3 -m models.whisper.convert_to_onnx -m openai/whisper-large-v3-turbo --output whisper-turbo --precision fp32 --provider cuda --use_gpu --use_external_data_format --optimize_onnx --no_beam_search_op --output_cross_qk + +# From wheel: +$ python3 -m onnxruntime.transformers.models.whisper.convert_to_onnx -m openai/whisper-large-v3-turbo --output whisper-turbo --precision fp32 --provider cuda --use_gpu --use_external_data_format --optimize_onnx --no_beam_search_op --output_cross_qk +``` + +Export + Optimize for FP16 CUDA +``` +# From source: +$ python3 -m models.whisper.convert_to_onnx -m openai/whisper-large-v3-turbo --output whisper-turbo --precision fp16 --provider cuda --use_gpu --use_external_data_format --optimize_onnx --no_beam_search_op --output_cross_qk + +# From wheel: +$ python3 -m onnxruntime.transformers.models.whisper.convert_to_onnx -m openai/whisper-large-v3-turbo --output whisper-turbo --precision fp16 --provider cuda --use_gpu --use_external_data_format --optimize_onnx --no_beam_search_op --output_cross_qk +``` + ## Exporting Whisper with Beam Search -There are several ways to export Whisper with beam search (using Whisper tiny as an example). +There are several ways to export Whisper with beam search. ### Option 1: from convert_to_onnx @@ -29,10 +85,10 @@ There are several ways to export Whisper with beam search (using Whisper tiny as # From source $ git clone https://github.com/microsoft/onnxruntime $ cd onnxruntime/onnxruntime/python/tools/transformers/ -$ python3 -m models.whisper.convert_to_onnx -m openai/whisper-large-v3 --output whisperlargev3 --use_external_data_format +$ python3 -m models.whisper.convert_to_onnx -m openai/whisper-large-v3-turbo --output whisper-turbo --use_external_data_format # From wheel -$ python3 -m onnxruntime.transformers.models.whisper.convert_to_onnx -m openai/whisper-large-v3 --output whisperlargev3 --use_external_data_format +$ python3 -m onnxruntime.transformers.models.whisper.convert_to_onnx -m openai/whisper-large-v3-turbo --output whisper-turbo --use_external_data_format ``` ### Option 2: end-to-end model from [Olive](https://github.com/microsoft/Olive/tree/main/examples/whisper) @@ -46,7 +102,7 @@ Run the following Python code to export: ``` from optimum.onnxruntime import ORTModelForSpeechSeq2Seq -model_name = "openai/whisper-large-v2" +model_name = "openai/whisper-large-v3-turbo" model = ORTModelForSpeechSeq2Seq.from_pretrained( model_name, export=True, @@ -58,51 +114,46 @@ model.save_pretrained(model_name.split("/")[-1] + "-onnx") Here are some additional examples for exporting Whisper with beam search. -To see all available options -``` -# From source: -$ python3 -m models.whisper.convert_to_onnx --help - -# From wheel: -$ python3 -m onnxruntime.transformers.models.whisper.convert_to_onnx --help -``` - Export with Forced Decoder Input Ids ``` # From source: -$ python3 -m models.whisper.convert_to_onnx -m openai/whisper-large-v3 --output whisperlargev3 --use_external_data_format --use_forced_decoder_ids +$ python3 -m models.whisper.convert_to_onnx -m openai/whisper-large-v3-turbo --output whisper-turbo --use_external_data_format --use_forced_decoder_ids # From wheel: -$ python3 -m onnxruntime.transformers.models.whisper.convert_to_onnx -m openai/whisper-large-v3 --output whisperlargev3 --use_external_data_format --use_forced_decoder_ids +$ python3 -m onnxruntime.transformers.models.whisper.convert_to_onnx -m openai/whisper-large-v3-turbo --output whisper-turbo --use_external_data_format --use_forced_decoder_ids ``` Export + Optimize for FP32 ``` # From source: -$ python3 -m models.whisper.convert_to_onnx -m openai/whisper-large-v3 --output whisperlargev3 --use_external_data_format --optimize_onnx --precision fp32 +$ python3 -m models.whisper.convert_to_onnx -m openai/whisper-large-v3-turbo --output whisper-turbo --use_external_data_format --optimize_onnx --precision fp32 # From wheel: -$ python3 -m onnxruntime.transformers.models.whisper.convert_to_onnx -m openai/whisper-large-v3 --output whisperlargev3 --use_external_data_format --optimize_onnx --precision fp32 +$ python3 -m onnxruntime.transformers.models.whisper.convert_to_onnx -m openai/whisper-large-v3-turbo --output whisper-turbo --use_external_data_format --optimize_onnx --precision fp32 ``` -Export + Optimize for FP16 and GPU +Note: FP32 CPU is not compatible with `--output_cross_qk`. + +Export + Optimize for FP16 GPU ``` # From source: -$ python3 -m models.whisper.convert_to_onnx -m openai/whisper-large-v3 --output whisperlargev3 --use_external_data_format --optimize_onnx --precision fp16 --use_gpu --provider cuda --disable_auto_mixed_precision +$ python3 -m models.whisper.convert_to_onnx -m openai/whisper-large-v3-turbo --output whisper-turbo --use_external_data_format --optimize_onnx --precision fp16 --use_gpu --provider cuda # From wheel: -$ python3 -m onnxruntime.transformers.models.whisper.convert_to_onnx -m openai/whisper-large-v3 --output whisperlargev3 --use_external_data_format --optimize_onnx --precision fp16 --use_gpu --provider cuda --disable_auto_mixed_precision +$ python3 -m onnxruntime.transformers.models.whisper.convert_to_onnx -m openai/whisper-large-v3-turbo --output whisper-turbo --use_external_data_format --optimize_onnx --precision fp16 --use_gpu --provider cuda ``` Export + Quantize for INT8 ``` # From source: -$ python3 -m models.whisper.convert_to_onnx -m openai/whisper-large-v3 --output whisperlargev3 --use_external_data_format --precision int8 --quantize_embedding_layer +$ python3 -m models.whisper.convert_to_onnx -m openai/whisper-large-v3-turbo --output whisper-turbo --use_external_data_format --precision int8 --quantize_embedding_layer # From wheel: -$ python3 -m onnxruntime.transformers.models.whisper.convert_to_onnx -m openai/whisper-large-v3 --output whisperlargev3 --use_external_data_format --precision int8 --quantize_embedding_layer +$ python3 -m onnxruntime.transformers.models.whisper.convert_to_onnx -m openai/whisper-large-v3-turbo --output whisper-turbo --use_external_data_format --precision int8 --quantize_embedding_layer ``` +Note: INT8 CPU is not compatible with `--output_cross_qk`. + ## Benchmark Whisper Here are some examples of how you can benchmark Whisper across various end-to-end (E2E) implementations. @@ -114,7 +165,7 @@ Here are some examples of how you can benchmark Whisper across various end-to-en python3 -m models.whisper.benchmark \ --benchmark-type hf-pt-eager \ --audio-path 1272-141231-0002.mp3 \ - --model-name openai/whisper-large-v2 \ + --model-name openai/whisper-large-v3-turbo \ --precision fp32 \ --device cpu ``` @@ -124,7 +175,7 @@ python3 -m models.whisper.benchmark \ python3 -m models.whisper.benchmark \ --benchmark-type hf-pt-compile \ --audio-path 1272-141231-0002.mp3 \ - --model-name openai/whisper-large-v2 \ + --model-name openai/whisper-large-v3-turbo \ --precision fp16 \ --device cuda ``` @@ -134,8 +185,8 @@ python3 -m models.whisper.benchmark \ python3 -m models.whisper.benchmark \ --benchmark-type hf-ort \ --audio-path 1272-141231-0002.mp3 \ - --model-name openai/whisper-large-v2 \ - --hf-ort-dir-path ./whisper-large-v2-onnx/ \ + --model-name openai/whisper-large-v3-turbo \ + --hf-ort-dir-path ./whisper-large-v3-turbo-onnx/ \ --precision fp32 \ --device cpu ``` @@ -145,8 +196,8 @@ python3 -m models.whisper.benchmark \ python3 -m models.whisper.benchmark \ --benchmark-type ort \ --audio-path 1272-141231-0002.mp3 \ - --model-name openai/whisper-large-v2 \ - --ort-model-path ./wlarge-fp32/whisper-large-v2_beamsearch.onnx \ + --model-name openai/whisper-large-v3-turbo \ + --ort-model-path ./wlarge-fp32/whisper-large-v3-turbo_beamsearch.onnx \ --precision fp32 \ --device cpu ``` @@ -156,7 +207,7 @@ python3 -m models.whisper.benchmark \ python3 -m models.whisper.benchmark \ --benchmark-type ort \ --audio-path 1272-141231-0002.mp3 \ - --model-name openai/whisper-large-v2 \ + --model-name openai/whisper-large-v3-turbo \ --ort-model-path ./wlarge-fp32/whisper-large_all.onnx \ --precision fp16 \ --device cuda @@ -167,8 +218,8 @@ python3 -m models.whisper.benchmark \ python3 -m models.whisper.benchmark \ --benchmark-type ort \ --audio-path 1272-141231-0002.mp3 \ - --model-name openai/whisper-large-v2 \ - --ort-model-path ./wlarge-fp32/whisper-large-v2_all.onnx \ + --model-name openai/whisper-large-v3-turbo \ + --ort-model-path ./wlarge-fp32/whisper-large-v3-turbo_all.onnx \ --precision fp32 \ --device cpu ``` @@ -184,9 +235,9 @@ python3 -m models.whisper.benchmark_all \ --audio-path ./whisper-test-audios/ \ --hf-pt-eager \ --hf-pt-compile \ - --hf-ort-dir-path ./whisper-large-v2-onnx/ \ - --ort-model-path ./wlarge-fp32/whisper-large-v2_all.onnx \ - --model-name openai/whisper-large-v2 \ + --hf-ort-dir-path ./whisper-large-v3-turbo-onnx/ \ + --ort-model-path ./wlarge-fp32/whisper-large-v3-turbo_all.onnx \ + --model-name openai/whisper-large-v3-turbo \ --precision fp32 \ --device cpu ``` diff --git a/onnxruntime/python/tools/transformers/models/whisper/convert_to_onnx.py b/onnxruntime/python/tools/transformers/models/whisper/convert_to_onnx.py index 3220f43ced152..2cc002928b16e 100644 --- a/onnxruntime/python/tools/transformers/models/whisper/convert_to_onnx.py +++ b/onnxruntime/python/tools/transformers/models/whisper/convert_to_onnx.py @@ -5,13 +5,13 @@ # -------------------------------------------------------------------------- import argparse -import copy import logging import os import torch from benchmark_helper import Precision, create_onnxruntime_session, prepare_environment, setup_logger from whisper_chain import chain_model +from whisper_encoder import WhisperEncoder from whisper_helper import PRETRAINED_WHISPER_MODELS, WhisperHelper from onnxruntime import quantization @@ -106,14 +106,6 @@ def parse_arguments(argv=None): ) conversion_args.set_defaults(use_int64_inputs=False) - conversion_args.add_argument( - "--disable_auto_mixed_precision", - required=False, - action="store_true", - help="Use pure fp16 instead of mixed precision", - ) - conversion_args.set_defaults(disable_auto_mixed_precision=False) - conversion_args.add_argument( "-r", "--provider", @@ -330,26 +322,36 @@ def export_onnx_models( verbose, use_forced_decoder_ids: bool = False, merge_encoder_and_decoder_init: bool = True, + no_beam_search_op: bool = False, + output_qk: bool = False, overwrite: bool = False, - disable_auto_mixed_precision: bool = False, use_int32_inputs: bool = True, quantize_embedding_layer: bool = False, quantize_per_channel: bool = False, quantize_reduce_range: bool = False, provider: str = "cpu", ): - device = torch.device("cuda:0" if use_gpu else "cpu") + device = torch.device("cuda" if use_gpu else "cpu") - models = WhisperHelper.load_model(model_name_or_path, model_impl, cache_dir, device, merge_encoder_and_decoder_init) + models = WhisperHelper.load_model( + model_name_or_path, + model_impl, + cache_dir, + device, + torch.float16 if precision == Precision.FLOAT16 else torch.float32, + merge_encoder_and_decoder_init, + no_beam_search_op, + output_qk, + ) config = models["decoder"].config if (not use_external_data_format) and (config.num_hidden_layers > 24): - logger.info("Try use_external_data_format when model size > 2GB") + logger.warning("You MUST pass `--use_external_data_format` because model size > 2GB") + raise Exception("Please pass `--use_external_data_format` for this model.") output_paths = [] for name, model in models.items(): print(f"========> Handling {name} model......") - model.to(device) filename_suffix = "_" + name onnx_path = WhisperHelper.get_onnx_path( @@ -359,23 +361,24 @@ def export_onnx_models( new_folder=False, ) + # Export to ONNX if overwrite or not os.path.exists(onnx_path): logger.info(f"Exporting ONNX model to {onnx_path}") - # We have to clone model before exporting onnx, otherwise verify_onnx will report large difference. - device_to_export = torch.device("cpu") - cloned_model = copy.deepcopy(model).to(device_to_export) WhisperHelper.export_onnx( - cloned_model, - device_to_export, + model, onnx_path, + PROVIDERS[provider], verbose, use_external_data_format, + use_fp16_inputs=(precision == Precision.FLOAT16), use_int32_inputs=use_int32_inputs, + use_encoder_hidden_states=(name == "decoder_init"), + use_kv_cache_inputs=(name == "decoder"), ) else: - logger.info(f"Skip exporting: existed ONNX model {onnx_path}") + logger.info(f"Skip exporting: existing ONNX model {onnx_path}") - # Optimize ONNX graph. Note that we have not implemented graph optimization for Whisper yet. + # Optimize ONNX model if optimize_onnx or precision != Precision.FLOAT32: output_path = WhisperHelper.get_onnx_path( output_dir, @@ -391,15 +394,37 @@ def export_onnx_models( onnx_path, output_path, precision == Precision.FLOAT16, - config.encoder_attention_heads, - config.d_model, + model.config.encoder_attention_heads, + model.config.d_model, + model.config.num_hidden_layers, use_external_data_format, - auto_mixed_precision=not disable_auto_mixed_precision, use_gpu=use_gpu, provider=provider, + is_decoder=(name == "decoder"), + no_beam_search_op=no_beam_search_op, + output_qk=output_qk, ) + # Remove old ONNX model and old data file + if os.path.exists(onnx_path): + os.remove(onnx_path) + if os.path.exists(onnx_path + ".data"): + os.remove(onnx_path + ".data") onnx_path = output_path + if isinstance(model, WhisperEncoder): + model.verify_onnx( + onnx_path, + PROVIDERS[provider], + use_fp16_inputs=(precision == Precision.FLOAT16), + ) + else: + model.verify_onnx( + onnx_path, + PROVIDERS[provider], + use_fp16_inputs=(precision == Precision.FLOAT16), + use_int32_inputs=use_int32_inputs, + ) + if precision == Precision.INT8: quantization.quantize_dynamic( onnx_path, @@ -417,13 +442,6 @@ def export_onnx_models( else: output_path = onnx_path - ort_session = create_onnxruntime_session( - output_path, - use_gpu=use_gpu, - provider=provider, - ) - assert ort_session is not None - output_paths.append(output_path) return output_paths @@ -443,9 +461,6 @@ def main(argv=None): if args.precision == Precision.FLOAT16: assert args.use_gpu, "fp16 requires --use_gpu" - if args.optimize_onnx: - logger.warning("Applying graph optimization for Whisper...") - output_paths = export_onnx_models( args.model_name_or_path, args.model_impl, @@ -458,8 +473,9 @@ def main(argv=None): args.verbose, args.use_forced_decoder_ids, not args.separate_encoder_and_decoder_init, + args.no_beam_search_op, + args.output_cross_qk, args.overwrite, - args.disable_auto_mixed_precision, not args.use_int64_inputs, args.quantize_embedding_layer, args.quantize_per_channel, @@ -477,7 +493,7 @@ def main(argv=None): new_folder=False, ) for path in output_paths: - if "encoder_decoder" in path: + if "encoder_decoder" in path or "encoder" in path: args.encoder_path = path elif "decoder" in path: args.decoder_path = path @@ -490,12 +506,12 @@ def main(argv=None): use_gpu=args.use_gpu, provider=args.provider, ) - device = torch.device("cuda:0" if args.use_gpu else "cpu") + device = torch.device("cuda" if args.use_gpu else "cpu") # Wrap parity check in try-except to allow export to continue in case this produces an error try: with torch.no_grad(): - # Verify batched decoding with prompts for whisper openai implementation + # Verify batched decoding with prompts for OpenAI implementation if args.model_impl == "openai" and args.use_forced_decoder_ids: max_diff = WhisperHelper.verify_onnx( args.model_name_or_path, cache_dir, ort_session, device, batch_size=2, prompt_mode=True @@ -512,10 +528,12 @@ def main(argv=None): ) # Remove extra ONNX models saved in output directory - for fle in os.listdir(output_dir): - if "_beamsearch" not in fle: - os.remove(os.path.join(output_dir, fle)) - output_paths = [args.beam_model_output_dir] + for _file in os.listdir(output_dir): + if "_beamsearch" not in _file and "_jump_times" not in _file: + path = os.path.join(output_dir, _file) + os.remove(path) + if path in output_paths: + output_paths.remove(path) logger.info(f"Done! Outputs: {output_paths}") return max_diff diff --git a/onnxruntime/python/tools/transformers/models/whisper/requirements.txt b/onnxruntime/python/tools/transformers/models/whisper/requirements.txt index 408b5b6c3a728..29a08b5ccd220 100644 --- a/onnxruntime/python/tools/transformers/models/whisper/requirements.txt +++ b/onnxruntime/python/tools/transformers/models/whisper/requirements.txt @@ -1,6 +1,6 @@ torch>=1.13.0 -transformers>=4.24.0,<= 4.42.4 -openai-whisper>=20231117 +transformers>=4.36.0,<= 4.42.4 +openai-whisper>=20231117,<=20240927 ffmpeg-python datasets soundfile diff --git a/onnxruntime/python/tools/transformers/models/whisper/whisper_chain.py b/onnxruntime/python/tools/transformers/models/whisper/whisper_chain.py index feb688948d8f5..365a69ee4ec67 100644 --- a/onnxruntime/python/tools/transformers/models/whisper/whisper_chain.py +++ b/onnxruntime/python/tools/transformers/models/whisper/whisper_chain.py @@ -312,13 +312,15 @@ def chain_model(args): # Save WhisperBeamSearch graph and external data if os.path.isfile(args.beam_model_output_dir): logger.info(f"Overwriting {args.beam_model_output_dir} and {args.beam_model_output_dir + '.data'}") - os.remove(args.beam_model_output_dir) - os.remove(args.beam_model_output_dir + ".data") + if os.path.exists(args.beam_model_output_dir): + os.remove(args.beam_model_output_dir) + if os.path.exists(args.beam_model_output_dir + ".data"): + os.remove(args.beam_model_output_dir + ".data") onnx.save( beam_model, args.beam_model_output_dir, - save_as_external_data=True, + save_as_external_data=args.use_external_data_format, all_tensors_to_one_file=True, convert_attribute=True, location=f"{os.path.basename(args.beam_model_output_dir)}.data", diff --git a/onnxruntime/python/tools/transformers/models/whisper/whisper_decoder.py b/onnxruntime/python/tools/transformers/models/whisper/whisper_decoder.py index 400cafc4c93c3..69683942656e0 100644 --- a/onnxruntime/python/tools/transformers/models/whisper/whisper_decoder.py +++ b/onnxruntime/python/tools/transformers/models/whisper/whisper_decoder.py @@ -7,395 +7,459 @@ import logging import os import tempfile +from itertools import chain from pathlib import Path -import numpy +import numpy as np import onnx import torch -from io_binding_helper import TypeHelper -from models.t5.past_helper import PastKeyValuesHelper +from float16 import convert_float_to_float16 +from google.protobuf.internal.containers import RepeatedCompositeFieldContainer +from onnx import ModelProto, ValueInfoProto from onnx_model import OnnxModel -from torch_onnx_export_helper import torch_onnx_export -from transformers import WhisperConfig, file_utils -from whisper_openai_helper import WhisperDecoderInitOpenai +from past_helper import PastKeyValuesHelper +from transformers import WhisperConfig +from whisper_inputs import ( + convert_inputs_for_ort, + get_model_dynamic_axes, + get_sample_decoder_inputs, + group_past_key_values, +) from onnxruntime import InferenceSession logger = logging.getLogger(__name__) -class WhisperDecoderInit(torch.nn.Module): - """A Whisper decoder to create initial past key values. - This model is only called once during starting decoding. - """ +class WhisperDecoder(torch.nn.Module): + """A Whisper decoder with optional past key values""" - def __init__( - self, - decoder: torch.nn.Module, - config: WhisperConfig, - decoder_start_token_id: int | None = None, - ): + def __init__(self, config: WhisperConfig, model: torch.nn.Module, model_impl: str, no_beam_search_op: bool = False): super().__init__() - self.decoder = decoder self.config = config - self.decoder_start_token_id = ( - decoder_start_token_id if decoder_start_token_id is not None else self.config.decoder_start_token_id - ) + self.device = model.device + self.model_impl = model_impl + self.no_beam_search_op = no_beam_search_op - def forward( + self.decoder = None if model_impl == "openai" else model.model.decoder + self.proj_out = None if model_impl == "openai" else model.proj_out + self.model = model if model_impl == "openai" else None + + self.max_source_positions = self.config.max_source_positions + self.num_heads = self.config.decoder_attention_heads + self.head_size = self.config.d_model // self.num_heads + + def hf_forward( self, decoder_input_ids: torch.Tensor, - encoder_hidden_states: torch.FloatTensor, + encoder_hidden_states: torch.Tensor | None = None, + past_key_values: list[tuple[torch.Tensor]] | None = None, ): - encoder_outputs = file_utils.ModelOutput() - encoder_outputs["last_hidden_state"] = encoder_hidden_states - encoder_outputs["hidden_states"] = None - encoder_outputs["attentions"] = None - - out = self.decoder.model( - None, - encoder_outputs=encoder_outputs, - decoder_input_ids=decoder_input_ids, - past_key_values=None, + outputs = self.decoder( + encoder_hidden_states=encoder_hidden_states, + input_ids=decoder_input_ids, + past_key_values=past_key_values, use_cache=True, - return_dict=True, ) - logits = self.decoder.proj_out(out[0]) - return logits, out.past_key_values, out.encoder_last_hidden_state - + logits = self.proj_out(outputs.last_hidden_state) + present_key_values = outputs.past_key_values -class WhisperDecoder(torch.nn.Module): - """A Whisper decoder with past key values""" + if past_key_values is None: + # Return present_self_* and present_cross_* for decoder-init + return logits, present_key_values - def __init__(self, decoder, config, model_impl: str = "hf", model: torch.nn.Module = None): - super().__init__() - self.decoder = decoder - self.config = config - self.model_impl = model_impl - if model is not None: - self.whisper_decoder_openai_init = WhisperDecoderInitOpenai(model, decoder) + # Before: (past_key_self_0, past_value_self_0, past_key_cross_0, past_value_cross_0), + # (past_key_self_1, past_value_self_1, past_key_cross_1, past_value_cross_1), + # After: (past_key_self_0, past_value_self_0, past_key_self_1, past_value_self_1), ..., + # (past_key_cross_0, past_value_cross_0, past_key_cross_1, past_value_cross_1), ... + present_self, present_cross = PastKeyValuesHelper.group_by_self_and_cross(present_key_values) - def forward(self, decoder_input_ids, *past): - encoder_outputs = file_utils.ModelOutput() - dummy_encoder_hidden_states = torch.randn((decoder_input_ids.shape[0], 3000, int(self.config.d_model))) - encoder_outputs["last_hidden_state"] = dummy_encoder_hidden_states - encoder_outputs["hidden_states"] = dummy_encoder_hidden_states - encoder_outputs["attentions"] = None + # Return present_self_* for decoder-with-past since past_cross_* and present_cross_* are identical + return logits, present_self - if self.model_impl == "openai": - dummy_encoder_hidden_states.unsqueeze(0) - dec_out, present = self.whisper_decoder_openai_init( - decoder_input_ids, dummy_encoder_hidden_states, past=past + def oai_forward( + self, + decoder_input_ids: torch.Tensor, + encoder_hidden_states: torch.Tensor | None = None, + past_key_values: list[tuple[torch.Tensor]] | None = None, + ): + past_kv_cache = {} + if past_key_values is not None: + # Convert past KV caches (BxNxSxH --> BxSxNxH --> BxSxD) for OpenAI's forward pass + self_attn_kv_caches, cross_attn_kv_caches = group_past_key_values(past_key_values) + self_attn_kv_caches = [past_kv.transpose(1, 2) for past_kv in self_attn_kv_caches] + self_attn_kv_caches = [past_kv.reshape(past_kv.shape[:2] + (-1,)) for past_kv in self_attn_kv_caches] + cross_attn_kv_caches = [past_kv.transpose(1, 2) for past_kv in cross_attn_kv_caches] + cross_attn_kv_caches = [past_kv.reshape(past_kv.shape[:2] + (-1,)) for past_kv in cross_attn_kv_caches] + + for idx, block in enumerate(self.model.decoder.blocks): + past_kv_cache[block.attn.key] = self_attn_kv_caches[2 * idx] + past_kv_cache[block.attn.value] = self_attn_kv_caches[2 * idx + 1] + past_kv_cache[block.cross_attn.key] = cross_attn_kv_caches[2 * idx] + past_kv_cache[block.cross_attn.value] = cross_attn_kv_caches[2 * idx + 1] + + # Install OpenAI's hooks on the forward pass of each nn.Linear for key and value + # since the hooks will capture the output of the key and value MatMuls, which + # represent the current keys and values. + # + # For OpenAI's forward pass, the hook function will also perform the concat + # operation (past_kv + curr_kv --> pres_kv) if needed. However, the ONNX model + # will not contain this concat operation because the present KV caches aren't + # returned by OpenAI's forward pass. + kv_cache, hooks = self.model.install_kv_cache_hooks() + + # Run forward pass + # NOTE: There is a bug with openai-whisper==20240930 with the introduction of SDPA. + # In the Whisper codebase, the following line + # + # is_causal = mask is not None and n_ctx > 1 + # + # has been added where `mask` is a torch tensor. The right-hand side evaluates to `tensor(True/False)` + # but `is_causal` only accepts the boolean value. The fix is to apply `.item()` after the right-hand + # side has been evaluated. In other words, the line should be + # + # is_causal = (mask is not None and n_ctx > 1).item() + # + # instead. + logits = self.model.decoder(x=decoder_input_ids, xa=encoder_hidden_states, kv_cache=past_kv_cache) + + # Re-do concat operation on self attention KV caches for ONNX export (if past self attention KV caches exist) + if past_key_values is not None: + for block in self.model.decoder.blocks: + kv_cache[block.attn.key] = torch.cat( + [past_kv_cache[block.attn.key], kv_cache[block.attn.key]], dim=1 + ).detach() + kv_cache[block.attn.value] = torch.cat( + [past_kv_cache[block.attn.value], kv_cache[block.attn.value]], dim=1 + ).detach() + + present_self, present_cross = [], [] + for block in self.model.decoder.blocks: + # Group self and cross values + present_self.append(kv_cache[block.attn.key]) + present_self.append(kv_cache[block.attn.value]) + if past_key_values is None: + # Return present_self_* and present_cross_* for decoder-init + present_cross.append(kv_cache[block.cross_attn.key]) + present_cross.append(kv_cache[block.cross_attn.value]) + + # Convert present KV caches (BxSxD --> BxSxNxH --> BxNxSxH) after OpenAI's forward pass + present_self = [ + present_kv.reshape(present_kv.shape[:2] + (-1, self.head_size)).transpose(1, 2) + for present_kv in present_self + ] + present_cross = [ + present_kv.reshape(present_kv.shape[:2] + (-1, self.head_size)).transpose(1, 2) + for present_kv in present_cross + ] + + # Remove OpenAI's hooks since they can persist after this function completes + for hook in hooks: + hook.remove() + + if past_key_values is None: + # Return present_self_* and present_cross_* for decoder-init + present_key_values = PastKeyValuesHelper.group_by_layer( + present_self + present_cross, len(present_self) // 2 ) - return dec_out, present - - if len(past) == 0: - past_key_values = None - else: - past_key_values = PastKeyValuesHelper.back_group_by_layer(past) + return logits, present_key_values - decoder_out = self.decoder( - None, - encoder_outputs=encoder_outputs, - decoder_input_ids=decoder_input_ids, - past_key_values=past_key_values, - use_cache=True, - return_dict=True, - ) - logits = decoder_out[0] - present_self, _ = PastKeyValuesHelper.group_by_self_and_cross(decoder_out.past_key_values) + # Return present_self_* for decoder-with-past since past_cross_* and present_cross_* are identical return logits, present_self - -class WhisperDecoderInputs: - def __init__( + def forward( self, - decoder_input_ids, - past_key_values=None, + decoder_input_ids: torch.Tensor, + encoder_hidden_states: torch.Tensor | None = None, + past_key_values: list[tuple[torch.Tensor]] | None = None, ): - self.decoder_input_ids: torch.LongTensor = decoder_input_ids - self.past_key_values: list[torch.FloatTensor] | list[torch.HalfTensor] | None = past_key_values - - @staticmethod - def create_dummy( - config: WhisperConfig, - batch_size: int, - encode_sequence_length: int, - past_decode_sequence_length: int, - device: torch.device, - float16: bool = False, - use_int32_inputs: bool = False, - model_impl: str = "hf", - ): # -> WhisperDecoderInputs: - """Create dummy inputs for WhisperDecoder. - - Args: - decoder: decoder - batch_size (int): batch size - encode_sequence_length (int): sequence length of input_ids for encoder - past_decode_sequence_length (int): past sequence length of input_ids for decoder - device (torch.device): device of output tensors - float16 (bool): whether the model uses float32 or float16 in input - use_int32_inputs(bool): whether use int32 instead of int64 for some inputs - - Returns: - WhisperDecoderInputs: dummy inputs for decoder - """ - num_attention_heads: int = config.encoder_attention_heads - num_layers: int = config.decoder_layers # + config.encoder_layers - vocab_size: int = config.vocab_size - - # Use head_size, use hidden_size / num_attention_heads here. - # For example, whisper-large, d_model=1280 and num_heads=20 - head_size: int = config.d_model // config.encoder_attention_heads - - sequence_length: int = 1 # fixed for decoding - decoder_input_ids = torch.randint( - low=0, - high=vocab_size - 1, - size=(batch_size, sequence_length), - dtype=(torch.int32 if use_int32_inputs else torch.int64), - device=device, - ) - - float_type = torch.float16 if float16 else torch.float32 + if self.model_impl == "openai": + return self.oai_forward(decoder_input_ids, encoder_hidden_states, past_key_values) + return self.hf_forward(decoder_input_ids, encoder_hidden_states, past_key_values) - if past_decode_sequence_length > 0: - self_attention_past_shape = [ - batch_size, - num_attention_heads, - past_decode_sequence_length, - head_size, + def input_names(self): + if self.first_pass: + input_names = ["input_ids", "encoder_hidden_states"] + else: + input_names = [ + "input_ids", + "encoder_hidden_states", + *list( + chain.from_iterable( + (f"past_key_self_{i}", f"past_value_self_{i}", f"past_key_cross_{i}", f"past_value_cross_{i}") + for i in range(self.config.num_hidden_layers) + ) + ), ] - cross_attention_past_shape = [ - batch_size, - num_attention_heads, - encode_sequence_length if model_impl == "hf" else past_decode_sequence_length, - head_size, + return input_names + + def output_names(self): + if self.first_pass: + output_names = [ + "logits", + *list( + chain.from_iterable( + ( + f"present_key_self_{i}", + f"present_value_self_{i}", + f"present_key_cross_{i}", + f"present_value_cross_{i}", + ) + for i in range(self.config.num_hidden_layers) + ) + ), ] - - past = [] - for _ in range(2 * num_layers): - past.append(torch.rand(self_attention_past_shape, dtype=float_type, device=device)) - - for _ in range(2 * num_layers): - past.append(torch.rand(cross_attention_past_shape, dtype=float_type, device=device)) else: - past = None - - return WhisperDecoderInputs(decoder_input_ids, past) - - def to_list(self) -> list: - input_list = [self.decoder_input_ids] - if self.past_key_values: - input_list.extend(self.past_key_values) - return input_list - - def to_fp32(self): - past = [p.to(dtype=torch.float32) for p in self.past_key_values] if self.past_key_values else None - return WhisperDecoderInputs( - self.decoder_input_ids.clone(), - past, + output_names = [ + "logits", + *list( + chain.from_iterable( + (f"present_key_self_{i}", f"present_value_self_{i}") + for i in range(self.config.num_hidden_layers) + ) + ), + ] + return output_names + + def dynamic_axes(self, input_names, output_names): + dynamic_axes = get_model_dynamic_axes(self.config, input_names, output_names) + if "input_ids" in dynamic_axes and not self.no_beam_search_op: + # Set dynamic axes for `input_ids` when using beam search op to {0: "batch_size"} only + del dynamic_axes["input_ids"][1] + return dynamic_axes + + def inputs(self, use_fp16_inputs: bool, use_int32_inputs: bool, return_dict: bool = False): + inputs = get_sample_decoder_inputs( + self.config, + self.device, + batch_size=2, + past_sequence_length=(0 if self.first_pass else 6), + sequence_length=(6 if self.first_pass else 1), + use_fp16=use_fp16_inputs, + use_int32=use_int32_inputs, + ) + if return_dict: + if self.first_pass: + del inputs["past_key_values"] + return inputs + + if self.first_pass: + return ( + inputs["decoder_input_ids"], + inputs["encoder_hidden_states"], + ) + return ( + inputs["decoder_input_ids"], + inputs["encoder_hidden_states"], + inputs["past_key_values"], ) + def fix_key_value_cache_dims(self, io: ValueInfoProto, is_cross: bool = False, is_output: bool = False): + # Shape should be (batch_size, num_heads, sequence_length, head_size) for self attention KV caches + # and (batch_size, num_heads, num_frames // 2, head_size) for cross attention KV caches + num_heads = io.type.tensor_type.shape.dim[1] + if "_dim_" in num_heads.dim_param: + num_heads.Clear() + num_heads.dim_value = self.num_heads + sequence_length = io.type.tensor_type.shape.dim[2] + if "_dim_" in sequence_length.dim_param: + sequence_length.Clear() + if is_cross: + sequence_length.dim_value = self.max_source_positions + else: + sequence_length.dim_param = "total_sequence_length" if is_output else "past_sequence_length" + head_size = io.type.tensor_type.shape.dim[3] + if "_dim_" in head_size.dim_param: + head_size.Clear() + head_size.dim_value = self.head_size + return io + + def fix_io(self, io_list: RepeatedCompositeFieldContainer, is_output: bool = False): + # Fix order of inputs/outputs and each dim_value of input/output + reordered_io = [] + self_attn_kv_caches = [] + cross_attn_kv_caches = [] + + for io in io_list: + if "past" not in io.name and "present" not in io.name: + reordered_io.append(io) + elif "self" in io.name: + # Self attention KV caches + new_io = self.fix_key_value_cache_dims(io, is_cross=False, is_output=is_output) + if self.no_beam_search_op: + reordered_io.append(new_io) + else: + self_attn_kv_caches.append(new_io) + else: + # Cross attention KV caches + new_io = self.fix_key_value_cache_dims(io, is_cross=True, is_output=is_output) + if self.no_beam_search_op: + reordered_io.append(new_io) + else: + cross_attn_kv_caches.append(new_io) + + if not self.no_beam_search_op: + reordered_io += self_attn_kv_caches + cross_attn_kv_caches + return reordered_io + + def fix_inputs_and_outputs(self, model: ModelProto): + # ONNX exporter might mark dimensions like 'Transposepresent_value_self_1_dim_2' in shape inference. + # We now change the dim_values to the correct one. + reordered_inputs = self.fix_io(model.graph.input, is_output=False) + while len(model.graph.input) > 0: + model.graph.input.pop() + model.graph.input.extend(reordered_inputs) + + reordered_outputs = self.fix_io(model.graph.output, is_output=True) + while len(model.graph.output) > 0: + model.graph.output.pop() + model.graph.output.extend(reordered_outputs) + return model + + def fix_layernorm_weights(self, model: ModelProto, use_fp16_inputs: bool): + if self.model_impl == "openai" and use_fp16_inputs: + # Cast ONNX model to float16 to ensure LayerNorm weights are converted from + # float32 to float16 since exported model already has float16 weights everywhere + # except for LayerNorm ops. This happens because OpenAI always upcasts to float32 + # when computing LayerNorm. + # + # Reference: + # https://github.com/openai/whisper/blob/90db0de1896c23cbfaf0c58bc2d30665f709f170/whisper/model.py#L41 + model = convert_float_to_float16(model) + return model -class WhisperDecoderHelper: - @staticmethod def export_onnx( - decoder: WhisperDecoder, - device: torch.device, + self, onnx_model_path: str, + provider: str, verbose: bool = True, use_external_data_format: bool = False, - use_int32_inputs: bool = False, + use_fp16_inputs: bool = False, + use_int32_inputs: bool = True, + use_encoder_hidden_states: bool = False, + use_kv_cache_inputs: bool = True, ): """Export decoder to ONNX Args: - decoder (Union[WhisperDecoder, WhisperDecoderNoPastState]): decoder object - device (torch.device): device of decoder object - onnx_model_path (str): onnx path + onnx_model_path (str): path to save ONNX model + provider (str): provider to use for verifying parity on ONNX model verbose (bool, optional): print verbose information. Defaults to True. use_external_data_format (bool, optional): use external data format or not. Defaults to False. - use_int32_inputs (bool, optional): use int32 inputs + use_fp16_inputs (bool, optional): use float16 inputs for the KV caches. Defaults to False. + use_int32_inputs (bool, optional): use int32 inputs for the decoder_input_ids. Defaults to True. + use_encoder_hidden_states (bool, optional): use encoder_hidden_states as model input for decoder-init/decoder-without-past models. Defaults to False. + use_kv_cache_inputs (bool, optional): use KV caches as model inputs for decoder-with-past models. Defaults to True. """ - assert isinstance(decoder, (WhisperDecoder, WhisperDecoderInit)) - - inputs = WhisperDecoderInputs.create_dummy( - decoder.config, - batch_size=2, - encode_sequence_length=3000, - past_decode_sequence_length=6 if isinstance(decoder, WhisperDecoder) else 0, - device=device, - use_int32_inputs=use_int32_inputs, - model_impl=decoder.model_impl, - ) - input_list = inputs.to_list() - - # Fix past disappearing bug - duplicate first past entry - # input_list.insert(2, input_list[2]) + # Shape of decoder's tensors: + # Required Inputs: + # decoder_input_ids: (batch_size, sequence_length) + # Optional Inputs: + # encoder_hidden_states (comes from encoder's outputs): (batch_size, num_frames // 2, hidden_size) + # past_{key/value}_self_* (past self attention KV caches): (batch_size, num_heads, past_sequence_length, head_size) + # past_{key/value}_cross_* (past cross attention KV caches): (batch_size, num_heads, num_frames // 2, head_size) + # Outputs: + # logits: (batch_size, sequence_length, vocab_size) + # present_{key/value}_self_* (present self attention KV caches): (batch_size, num_heads, past_sequence_length + sequence_length, head_size) + # present_{key/value}_cross_* (present cross attention KV caches): (batch_size, num_heads, num_frames // 2, head_size) - past_names = PastKeyValuesHelper.get_past_names(decoder.config.decoder_layers, present=False) - present_names = PastKeyValuesHelper.get_past_names(decoder.config.decoder_layers, present=True) - present_self_names = present_names[: 2 * decoder.config.decoder_layers] + # For the first pass through the decoder (i.e. decoder-init/decoder-without-past) + self.first_pass = use_encoder_hidden_states and not use_kv_cache_inputs - input_past_names = past_names if isinstance(decoder, WhisperDecoder) else [] - output_present_names = present_self_names if isinstance(decoder, WhisperDecoder) else present_names - output_names = ["logits", *output_present_names] + # For subsequent passes through the decoder (i.e. decoder-with-past) + self.later_pass = not use_encoder_hidden_states and use_kv_cache_inputs - # Shape of input tensors (sequence_length==1): - # input_ids: (batch_size, sequence_length) - # past_self_*: (batch_size, num_heads, past_decode_sequence_length, head_size) - # past_cross_*: (batch_size, num_heads, encode_sequence_length, head_size) + assert self.first_pass or self.later_pass, ( + "Only one of `use_encoder_hidden_states` and `use_kv_cache_inputs` can be true at once." + ) - # Shape of output tensors: - # logits: (batch_size, sequence_length, vocab_size) - # past_self_*: (batch_size, num_heads, past_decode_sequence_length + sequence_length, head_size) - # past_cross_*: (batch_size, num_heads, encode_sequence_length, head_size) - - input_names = ["input_ids"] - input_names.extend(input_past_names) - - dynamic_axes = { - "input_ids": {0: "batch_size"}, - "encoder_hidden_states": {0: "batch_size", 1: "encode_sequence_length / 2"}, - "logits": {0: "batch_size", 1: "sequence_length"}, - } - - for name in input_past_names: - dynamic_axes[name] = { - 0: "batch_size", - 2: "past_decode_sequence_length" if "self" in name else "encode_sequence_length", - } - - for name in output_present_names: - if "cross" in name: - dynamic_axes[name] = {0: "batch_size", 2: "encode_sequence_length"} - else: # self attention past state - if isinstance(decoder, WhisperDecoder): - dynamic_axes[name] = { - 0: "batch_size", - 2: "past_decode_sequence_length + 1", - } - else: - dynamic_axes[name] = { - 0: "batch_size", - # 2: 'sequence_length' - } + inputs = self.inputs(use_fp16_inputs=use_fp16_inputs, use_int32_inputs=use_int32_inputs) + input_names = self.input_names() + output_names = self.output_names() + dynamic_axes = self.dynamic_axes(input_names, output_names) Path(onnx_model_path).parent.mkdir(parents=True, exist_ok=True) - with tempfile.TemporaryDirectory() as tmp_dir_name: temp_onnx_model_path = os.path.join(tmp_dir_name, "decoder.onnx") Path(temp_onnx_model_path).parent.mkdir(parents=True, exist_ok=True) - torch_onnx_export( - decoder, - args=tuple(input_list), - f=temp_onnx_model_path if use_external_data_format else onnx_model_path, + out_path = temp_onnx_model_path if use_external_data_format else onnx_model_path + + torch.onnx.export( + self, + args=inputs, + f=out_path, export_params=True, input_names=input_names, output_names=output_names, dynamic_axes=dynamic_axes, opset_version=17, do_constant_folding=True, - use_external_data_format=use_external_data_format, verbose=verbose, ) - if use_external_data_format: - model = onnx.load_model(temp_onnx_model_path, load_external_data=True) - OnnxModel.save( - model, - onnx_model_path, - save_as_external_data=True, - all_tensors_to_one_file=True, - ) - - @staticmethod - def onnxruntime_inference(ort_session, inputs: WhisperDecoderInputs): - """Run inference of ONNX model.""" - logger.debug("start onnxruntime_inference") - - ort_inputs = { - "input_ids": numpy.ascontiguousarray(inputs.decoder_input_ids.cpu().numpy()), - } - - if inputs.past_key_values: - assert len(inputs.past_key_values) % 4 == 0 - num_layers = int(len(inputs.past_key_values) / 4) - past_names = PastKeyValuesHelper.get_past_names(num_layers) - for i, past_tensor in enumerate(inputs.past_key_values): - ort_inputs[past_names[i]] = numpy.ascontiguousarray(past_tensor.cpu().numpy()) - - ort_outputs = ort_session.run(None, ort_inputs) - return ort_outputs - - @staticmethod - def verify_onnx( - model: WhisperDecoder | WhisperDecoderInit, - ort_session: InferenceSession, - device: torch.device, - use_int32_inputs: bool, - max_cases: int = 4, - ): - """Compare the result from PyTorch and OnnxRuntime to verify the ONNX model is good.""" - float16: bool = TypeHelper.get_input_type(ort_session, "past_key_self_0") == "tensor(float16)" - - test_cases = [(4, 11, 3), (1, 2, 5), (3, 1, 1), (8, 5, 2)] - test_cases_max_diff = [] - for ( - batch_size, - encode_sequence_length, - past_decode_sequence_length, - ) in test_cases[:max_cases]: - if isinstance(model, WhisperDecoderInit): - dec_seq_len = 0 - else: - dec_seq_len = past_decode_sequence_length - - inputs = WhisperDecoderInputs.create_dummy( - model.config, - batch_size, - encode_sequence_length, - dec_seq_len, - device=device, - float16=float16, - use_int32_inputs=use_int32_inputs, + model = onnx.load_model(out_path, load_external_data=use_external_data_format) + model = self.fix_inputs_and_outputs(model) + model = self.fix_layernorm_weights(model, use_fp16_inputs) + OnnxModel.save( + model, + onnx_model_path, + save_as_external_data=use_external_data_format, + all_tensors_to_one_file=True, ) - # We use fp32 PyTroch model as baseline even when ONNX model is fp16 - input_list = inputs.to_fp32().to_list() + self.verify_onnx(onnx_model_path, provider, use_fp16_inputs, use_int32_inputs) - # Run inference of PyTorch model - with torch.no_grad(): - torch_outputs = model(*input_list) - - ort_outputs = WhisperDecoderHelper.onnxruntime_inference(ort_session, inputs) - - max_diff = numpy.amax(numpy.abs(torch_outputs[0].cpu().numpy() - ort_outputs[0])) - max_diff_all = max_diff - logger.debug(f"logits max_diff={max_diff}") - - for i in range(2 * model.config.num_layers): - max_diff = numpy.amax(numpy.abs(torch_outputs[1][i].cpu().numpy() - ort_outputs[1 + i])) - logger.debug(f"self attention past state {i} max_diff={max_diff}") - max_diff_all = max(max_diff_all, max_diff) - - if isinstance(model, WhisperDecoderInit): - for i in range(2 * model.config.num_layers): - max_diff = numpy.amax( - numpy.abs(torch_outputs[2][i].cpu().numpy() - ort_outputs[1 + 2 * model.config.num_layers + i]) - ) - logger.debug(f"cross attention past state {i} max_diff={max_diff}") - max_diff_all = max(max_diff_all, max_diff) - - test_cases_max_diff.append(max_diff_all) - logger.info( - "batch_size=%s, encode_sequence_length=%s, past_decode_sequence_length=%s, max_diff=%s", - batch_size, - encode_sequence_length, - past_decode_sequence_length, - max_diff_all, - ) + def verify_onnx( + self, + onnx_model_path: str, + provider: str, + use_fp16_inputs: bool, + use_int32_inputs: bool, + ): + """Verify ONNX model outputs and PyTorch model outputs match - return max_diff_all + Args: + onnx_model_path (str): path to save ONNX model + provider (str): execution provider for ONNX model + use_fp16_inputs (bool, optional): use float16 inputs for the KV caches + use_int32_inputs (bool, optional): use int32 inputs for the decoder_input_ids + """ + # Shape of decoder's tensors: + # Required Inputs: + # decoder_input_ids: (batch_size, sequence_length) + # Optional Inputs: + # encoder_hidden_states (comes from encoder's outputs): (batch_size, num_frames // 2, hidden_size) + # past_{key/value}_self_* (past self attention KV caches): (batch_size, num_heads, past_sequence_length, head_size) + # past_{key/value}_cross_* (past cross attention KV caches): (batch_size, num_heads, num_frames // 2, head_size) + # Outputs: + # logits: (batch_size, sequence_length, vocab_size) + # present_{key/value}_self_* (present self attention KV caches): (batch_size, num_heads, past_sequence_length + sequence_length, head_size) + # present_{key/value}_cross_* (present cross attention KV caches): (batch_size, num_heads, num_frames // 2, head_size) + + # Run PyTorch model + inputs = self.inputs(use_fp16_inputs=use_fp16_inputs, use_int32_inputs=use_int32_inputs, return_dict=True) + pt_outputs = [] + if self.first_pass: + out = self.forward(**inputs) + pt_outputs.append(out[0].detach().cpu().numpy()) + for present_key_value_layer in out[1]: + for present_key_value in present_key_value_layer: + pt_outputs.append(present_key_value.detach().cpu().numpy()) + else: + out = self.forward(**inputs) + pt_outputs.append(out[0].detach().cpu().numpy()) + for present_self_key_value in out[1]: + pt_outputs.append(present_self_key_value.detach().cpu().numpy()) + + # Run ONNX model + sess = InferenceSession(onnx_model_path, providers=[provider]) + ort_outputs = sess.run(None, convert_inputs_for_ort(inputs, sess)) + + # Calculate output difference + try: + for i, output_name in enumerate(self.output_names()): + diff = np.abs(pt_outputs[i] - ort_outputs[i]) + logger.warning(f"Comparing {output_name}...") + logger.warning(f"Max diff: {np.max(diff)}") + except: # noqa: E722 + pass diff --git a/onnxruntime/python/tools/transformers/models/whisper/whisper_encoder.py b/onnxruntime/python/tools/transformers/models/whisper/whisper_encoder.py index 0b9db81486caa..851f641442016 100644 --- a/onnxruntime/python/tools/transformers/models/whisper/whisper_encoder.py +++ b/onnxruntime/python/tools/transformers/models/whisper/whisper_encoder.py @@ -9,12 +9,14 @@ import tempfile from pathlib import Path -import numpy +import numpy as np import onnx import torch +from float16 import convert_float_to_float16 +from onnx import ModelProto from onnx_model import OnnxModel -from torch_onnx_export_helper import torch_onnx_export from transformers import WhisperConfig +from whisper_inputs import get_model_dynamic_axes, get_sample_encoder_inputs from onnxruntime import InferenceSession @@ -22,142 +24,141 @@ class WhisperEncoder(torch.nn.Module): - """Whisper encoder outputs only the last hidden state""" + """Whisper encoder component""" - def __init__(self, encoder, config: WhisperConfig, model_impl: str = "hf"): + def __init__(self, config: WhisperConfig, model: torch.nn.Module, model_impl: str): super().__init__() - self.encoder = encoder self.config = config + self.device = model.device self.model_impl = model_impl - def forward(self, input_features): - if self.model_impl == "openai": - return self.encoder(input_features) - return self.encoder.model.encoder(input_features)[0] + self.encoder = model.encoder if model_impl == "openai" else model.model.encoder + def forward(self, audio_features: torch.Tensor): + outputs = self.encoder(audio_features) + return outputs if self.model_impl == "openai" else outputs.last_hidden_state -class WhisperEncoderInputs: - def __init__(self, input_features): - self.input_ids: torch.LongTensor = input_features + def input_names(self): + input_names = ["audio_features"] + return input_names - @staticmethod - def create_dummy( - batch_size: int, - sequence_length: int, - feature_size: int, - device: torch.device, - use_int32_inputs: bool = False, - ): - """Create dummy inputs for Whisper encoder. - - Args: - batch_size (int): batch size - sequence_length (int): sequence length - feature_size (int): feature size for spectrogram input - device (torch.device): device of output tensors - - Returns: - WhisperEncoderInputs: dummy inputs for encoder - """ + def output_names(self): + output_names = ["encoder_hidden_states"] + return output_names - input_features = torch.randn( - size=(batch_size, feature_size, sequence_length), - device=device, - ) - return WhisperEncoderInputs(input_features) - - def to_list(self) -> list: - if self.input_ids is None: - return [] - return [self.input_ids] + def dynamic_axes(self, input_names, output_names): + dynamic_axes = get_model_dynamic_axes(self.config, input_names, output_names) + return dynamic_axes + def fix_layernorm_weights(self, model: ModelProto, use_fp16_inputs: bool): + if self.model_impl == "openai" and use_fp16_inputs: + # Cast ONNX model to float16 to ensure LayerNorm weights are converted from + # float32 to float16 since exported model already has float16 weights everywhere + # except for LayerNorm ops. This happens because OpenAI always upcasts to float32 + # when computing LayerNorm. + # + # Reference: + # https://github.com/openai/whisper/blob/90db0de1896c23cbfaf0c58bc2d30665f709f170/whisper/model.py#L41 + model = convert_float_to_float16(model) + return model -class WhisperEncoderHelper: - @staticmethod def export_onnx( - encoder, - device: torch.device, + self, onnx_model_path: str, + provider: str, verbose: bool = True, use_external_data_format: bool = False, - use_int32_inputs: bool = False, + use_fp16_inputs: bool = False, ): """Export encoder to ONNX Args: - encoder (WhisperEncoder): encoder object - device (torch.device): device of encoder object - onnx_model_path (str): onnx path + onnx_model_path (str): path to save ONNX model + provider (str): provider to use for verifying parity on ONNX model verbose (bool, optional): print verbose information. Defaults to True. use_external_data_format (bool, optional): use external data format or not. Defaults to False. + use_fp16_inputs (bool, optional): use float16 inputs for the audio_features. Defaults to False. """ - config = encoder.config - encoder_inputs = WhisperEncoderInputs.create_dummy( + # Shape of encoder's tensors: + # Inputs: + # audio_features: (batch_size, num_mels, num_frames) + # Outputs: + # encoder_hidden_states: (batch_size, num_frames // 2, hidden_size) + + inputs = get_sample_encoder_inputs( + self.config, + self.device, batch_size=2, - sequence_length=3000, - feature_size=config.num_mel_bins, - device=device, - use_int32_inputs=use_int32_inputs, + use_fp16=use_fp16_inputs, ) - Path(onnx_model_path).parent.mkdir(parents=True, exist_ok=True) + input_names = self.input_names() + output_names = self.output_names() + dynamic_axes = self.dynamic_axes(input_names, output_names) + Path(onnx_model_path).parent.mkdir(parents=True, exist_ok=True) with tempfile.TemporaryDirectory() as tmp_dir_name: temp_onnx_model_path = os.path.join(tmp_dir_name, "encoder.onnx") Path(temp_onnx_model_path).parent.mkdir(parents=True, exist_ok=True) - torch_onnx_export( - encoder, - args=tuple(encoder_inputs.to_list()), - f=temp_onnx_model_path if use_external_data_format else onnx_model_path, + out_path = temp_onnx_model_path if use_external_data_format else onnx_model_path + + torch.onnx.export( + self, + args=(inputs["audio_features"]), + f=out_path, export_params=True, - input_names=["input_features"], - output_names=["hidden_states"], - dynamic_axes={ - "input_ids": {0: "batch_size", 1: "feature_size", 2: "sequence_length"}, - "hidden_states": {0: "batch_size", 1: "sequence_length"}, - }, + input_names=input_names, + output_names=output_names, + dynamic_axes=dynamic_axes, opset_version=17, do_constant_folding=True, - use_external_data_format=use_external_data_format, verbose=verbose, ) - if use_external_data_format: - model = onnx.load_model(temp_onnx_model_path, load_external_data=True) - OnnxModel.save( - model, - onnx_model_path, - save_as_external_data=True, - all_tensors_to_one_file=True, - ) - - @staticmethod - def onnxruntime_inference(ort_session, inputs: WhisperEncoderInputs): - """Run inference of ONNX model.""" - ort_inputs = { - "input_ids": numpy.ascontiguousarray(inputs.input_ids.cpu().numpy()), - } - - return ort_session.run(None, ort_inputs) - - @staticmethod + model = onnx.load_model(out_path, load_external_data=use_external_data_format) + model = self.fix_layernorm_weights(model, use_fp16_inputs) + OnnxModel.save( + model, + onnx_model_path, + save_as_external_data=use_external_data_format, + all_tensors_to_one_file=True, + ) + + self.verify_onnx(onnx_model_path, provider, use_fp16_inputs) + def verify_onnx( - model: WhisperEncoder, ort_session: InferenceSession, device: torch.device, use_int32_inputs: bool = False + self, + onnx_model_path: str, + provider: str, + use_fp16_inputs: bool, ): - """Compare the result from PyTorch and OnnxRuntime to verify the ONNX model is good.""" - inputs = WhisperEncoderInputs.create_dummy( - batch_size=4, - sequence_length=11, - device=device, - use_int32_inputs=use_int32_inputs, - ) - input_list = inputs.to_list() - torch_outputs = model(*input_list) + """Verify ONNX model outputs and PyTorch model outputs match - ort_outputs = WhisperEncoderHelper.onnxruntime_inference(ort_session, inputs) + Args: + onnx_model_path (str): path to save ONNX model + provider (str): execution provider for ONNX model + use_fp16_inputs (bool, optional): use float16 inputs for the audio_features + """ + # Shape of encoder's tensors: + # Inputs: + # audio_features: (batch_size, num_mels, num_frames) + # Outputs: + # encoder_hidden_states: (batch_size, num_frames // 2, hidden_size) + inputs = get_sample_encoder_inputs( + self.config, + self.device, + batch_size=2, + use_fp16=use_fp16_inputs, + ) - max_diff = numpy.amax(numpy.abs(torch_outputs.cpu().numpy() - ort_outputs[0])) + # Run PyTorch model + pt_outputs = self.forward(inputs["audio_features"]).detach().cpu().numpy() - logger.info(f"max_diff={max_diff}") + # Run ONNX model + sess = InferenceSession(onnx_model_path, providers=[provider]) + ort_outputs = sess.run(None, {"audio_features": inputs["audio_features"].detach().cpu().numpy()})[0] - return max_diff + # Calculate output difference + diff = np.abs(pt_outputs - ort_outputs) + logger.warning("Comparing encoder_hidden_states...") + logger.warning(f"Max diff: {np.max(diff)}") diff --git a/onnxruntime/python/tools/transformers/models/whisper/whisper_encoder_decoder_init.py b/onnxruntime/python/tools/transformers/models/whisper/whisper_encoder_decoder_init.py index c7c7a7675c1a7..26dc3aee7018b 100644 --- a/onnxruntime/python/tools/transformers/models/whisper/whisper_encoder_decoder_init.py +++ b/onnxruntime/python/tools/transformers/models/whisper/whisper_encoder_decoder_init.py @@ -7,18 +7,24 @@ import logging import os import tempfile +from itertools import chain from pathlib import Path -import numpy +import numpy as np import onnx import torch -from models.t5.past_helper import PastKeyValuesHelper +from float16 import convert_float_to_float16 +from onnx import ModelProto, ValueInfoProto from onnx_model import OnnxModel -from torch_onnx_export_helper import torch_onnx_export from transformers import WhisperConfig -from whisper_decoder import WhisperDecoderInit -from whisper_encoder import WhisperEncoder, WhisperEncoderInputs -from whisper_openai_helper import WhisperDecoderInitOpenai +from whisper_decoder import WhisperDecoder +from whisper_encoder import WhisperEncoder +from whisper_inputs import ( + convert_inputs_for_ort, + get_model_dynamic_axes, + get_sample_encoder_decoder_init_inputs, + group_past_key_values, +) from onnxruntime import InferenceSession @@ -26,205 +32,275 @@ class WhisperEncoderDecoderInit(torch.nn.Module): - """A combination of WhisperEncoder and WhisperDecoderInit.""" + """Whisper encoder component + first pass through Whisper decoder component to initialize KV caches""" - def __init__( - self, - encoder: torch.nn.Module, - decoder: torch.nn.Module, - config: WhisperConfig, - decoder_start_token_id: int | None = None, - model_impl: str = "hf", - model: torch.nn.Module = None, - ): + def __init__(self, config: WhisperConfig, model: torch.nn.Module, model_impl: str, no_beam_search_op: bool = False): super().__init__() self.config = config - self.whisper_encoder = WhisperEncoder(encoder, config, model_impl=model_impl) - self.whisper_decoder_init = WhisperDecoderInit(decoder, config, decoder_start_token_id) - if model is not None: - self.whisper_decoder_openai_init = WhisperDecoderInitOpenai(model, decoder) + self.device = model.device self.model_impl = model_impl + self.no_beam_search_op = no_beam_search_op + + self.encoder = WhisperEncoder(config, model, model_impl) + self.decoder = WhisperDecoder(config, model, model_impl, no_beam_search_op) + + self.max_source_positions = self.config.max_source_positions + self.num_heads = self.config.decoder_attention_heads + self.head_size = self.config.d_model // self.num_heads + + def hf_forward_for_beam_search_op(self, audio_features: torch.Tensor, decoder_input_ids: torch.Tensor): + encoder_hidden_states = self.encoder(audio_features) + logits, present_key_values = self.decoder(decoder_input_ids, encoder_hidden_states) + return logits, encoder_hidden_states, present_key_values + + def hf_forward_for_no_beam_search_op(self, audio_features: torch.Tensor): + encoder_hidden_states = self.encoder(audio_features) + + # Get cross attention KV caches and return them for this model + # We do this because these MatMuls are only run once before their outputs are being re-used in the decoder + present_cross_attention_key_value_caches = [] + for layer in self.decoder.decoder.layers: + cross_attn_key_cache = ( + layer.encoder_attn.k_proj(encoder_hidden_states) + .view(-1, self.max_source_positions, self.num_heads, self.head_size) + .transpose(1, 2) + ) + cross_attn_value_cache = ( + layer.encoder_attn.v_proj(encoder_hidden_states) + .view(-1, self.max_source_positions, self.num_heads, self.head_size) + .transpose(1, 2) + ) + present_cross_attention_key_value_caches.append(cross_attn_key_cache) + present_cross_attention_key_value_caches.append(cross_attn_value_cache) + + return encoder_hidden_states, present_cross_attention_key_value_caches + + def oai_forward_for_beam_search_op(self, audio_features: torch.Tensor, decoder_input_ids: torch.Tensor): + encoder_hidden_states = self.encoder(audio_features) + logits, present_key_values = self.decoder(decoder_input_ids, encoder_hidden_states) + return logits, encoder_hidden_states, present_key_values + + def oai_forward_for_no_beam_search_op(self, audio_features: torch.Tensor): + encoder_hidden_states = self.encoder(audio_features) + + # Get cross attention KV caches and return them for this model + # We do this because these MatMuls are only run once before their outputs are being re-used in the decoder + present_cross_attention_key_value_caches = [] + for block in self.decoder.model.decoder.blocks: + cross_attn_key_cache = ( + block.cross_attn.key(encoder_hidden_states) + .view(-1, self.max_source_positions, self.num_heads, self.head_size) + .transpose(1, 2) + ) + cross_attn_value_cache = ( + block.cross_attn.value(encoder_hidden_states) + .view(-1, self.max_source_positions, self.num_heads, self.head_size) + .transpose(1, 2) + ) + present_cross_attention_key_value_caches.append(cross_attn_key_cache) + present_cross_attention_key_value_caches.append(cross_attn_value_cache) - def forward( - self, - encoder_input_ids: torch.Tensor, - decoder_input_ids: torch.Tensor = None, - remove_hooks: bool = False, - ): - encoder_hidden_states: torch.FloatTensor = self.whisper_encoder(encoder_input_ids) - # Decoder out: (logits, past_key_values, encoder_hidden_state) + return encoder_hidden_states, present_cross_attention_key_value_caches + + def forward(self, audio_features: torch.Tensor, decoder_input_ids: torch.Tensor | None = None): if self.model_impl == "openai": - encoder_hidden_states.unsqueeze(0) - decinit_out, present = self.whisper_decoder_openai_init( - decoder_input_ids, encoder_hidden_states, remove_hooks=remove_hooks - ) - return decinit_out, encoder_hidden_states, present + if self.no_beam_search_op: + return self.oai_forward_for_no_beam_search_op(audio_features) + return self.oai_forward_for_beam_search_op(audio_features, decoder_input_ids) + + # Hugging Face implementation + if self.no_beam_search_op: + return self.hf_forward_for_no_beam_search_op(audio_features) + return self.hf_forward_for_beam_search_op(audio_features, decoder_input_ids) + + def input_names(self): + if self.no_beam_search_op: + input_names = ["audio_features"] + else: + input_names = ["encoder_input_ids", "decoder_input_ids"] + return input_names + + def output_names(self): + if self.no_beam_search_op: + output_names = [ + "encoder_hidden_states", + *list( + chain.from_iterable( + (f"present_key_cross_{i}", f"present_value_cross_{i}") + for i in range(self.config.num_hidden_layers) + ) + ), + ] else: - decinit_out = self.whisper_decoder_init(decoder_input_ids, encoder_hidden_states) - present_self, present_cross = PastKeyValuesHelper.group_by_self_and_cross(decinit_out[1]) - present = present_self + present_cross - return decinit_out[0], encoder_hidden_states, present - - -class WhisperEncoderDecoderInitInputs: - def __init__(self, encoder_input_ids, decoder_input_ids=None): - self.encoder_input_ids: torch.LongTensor = encoder_input_ids - self.decoder_input_ids: torch.LongTensor = decoder_input_ids - - @staticmethod - def create_dummy( - config: WhisperConfig, - batch_size: int, - encode_sequence_length: int, - use_decoder_input_ids: bool, - device: torch.device, - use_int32_inputs: bool = False, - ): # -> WhisperEncoderDecoderInitInputs: - encoder_inputs: WhisperEncoderInputs = WhisperEncoderInputs.create_dummy( - batch_size, - sequence_length=3000, - feature_size=config.num_mel_bins, - device=device, + output_names = [ + "logits", + "encoder_hidden_states", + *list( + chain.from_iterable( + ( + f"present_key_self_{i}", + f"present_value_self_{i}", + f"present_key_cross_{i}", + f"present_value_cross_{i}", + ) + for i in range(self.config.num_hidden_layers) + ) + ), + ] + return output_names + + def dynamic_axes(self, input_names, output_names): + dynamic_axes = get_model_dynamic_axes(self.config, input_names, output_names) + return dynamic_axes + + def inputs(self, use_fp16_inputs: bool, use_int32_inputs: bool, return_dict: bool = False): + inputs = get_sample_encoder_decoder_init_inputs( + self.config, + self.device, + batch_size=2, + decoder_sequence_length=6, + use_fp16=use_fp16_inputs, + use_int32=use_int32_inputs, + ) + if return_dict: + if self.no_beam_search_op: + del inputs["decoder_input_ids"] + return inputs + + if self.no_beam_search_op: + return (inputs["audio_features"],) + return ( + inputs["audio_features"], + inputs["decoder_input_ids"], ) - decoder_input_ids = None - if use_decoder_input_ids: - dtype = torch.int32 if use_int32_inputs else torch.int64 - decoder_input_ids = torch.ones((batch_size, 2), dtype=dtype, device=device) * config.decoder_start_token_id - - return WhisperEncoderDecoderInitInputs(encoder_inputs.input_ids, decoder_input_ids) - - def to_list(self) -> list: - input_list = [self.encoder_input_ids] - if self.decoder_input_ids is not None: - input_list.append(self.decoder_input_ids) - return input_list + def fix_key_value_cache_dims(self, output: ValueInfoProto, is_cross: bool = False): + # Shape should be (batch_size, num_heads, sequence_length, head_size) for self attention KV caches + # and (batch_size, num_heads, num_frames // 2, head_size) for cross attention KV caches + num_heads = output.type.tensor_type.shape.dim[1] + if "_dim_" in num_heads.dim_param: + num_heads.Clear() + num_heads.dim_value = self.num_heads + sequence_length = output.type.tensor_type.shape.dim[2] + if "_dim_" in sequence_length.dim_param: + sequence_length.Clear() + if is_cross: + sequence_length.dim_value = self.max_source_positions + else: + sequence_length.dim_param = "total_sequence_length" + head_size = output.type.tensor_type.shape.dim[3] + if "_dim_" in head_size.dim_param: + head_size.Clear() + head_size.dim_value = self.head_size + return output + + def fix_outputs(self, model: ModelProto): + # ONNX exporter might mark dimensions like 'Transposepresent_value_self_1_dim_2' in shape inference. + # We now change the dim_values to the correct one. + reordered_outputs = [] + self_attn_kv_caches = [] + cross_attn_kv_caches = [] + + for output in model.graph.output: + if "present" not in output.name: + reordered_outputs.append(output) + + elif "self" in output.name: + # Self attention KV caches + new_output = self.fix_key_value_cache_dims(output, is_cross=False) + if self.no_beam_search_op: + reordered_outputs.append(new_output) + else: + self_attn_kv_caches.append(new_output) + else: + # Cross attention KV caches + new_output = self.fix_key_value_cache_dims(output, is_cross=True) + if self.no_beam_search_op: + reordered_outputs.append(new_output) + else: + cross_attn_kv_caches.append(new_output) + + if not self.no_beam_search_op: + reordered_outputs += self_attn_kv_caches + cross_attn_kv_caches + + while len(model.graph.output) > 0: + model.graph.output.pop() + model.graph.output.extend(reordered_outputs) + return model + + def fix_layernorm_weights(self, model: ModelProto, use_fp16_inputs: bool): + if self.model_impl == "openai" and use_fp16_inputs: + # Cast ONNX model to float16 to ensure LayerNorm weights are converted from + # float32 to float16 since exported model already has float16 weights everywhere + # except for LayerNorm ops. This happens because OpenAI always upcasts to float32 + # when computing LayerNorm. + # + # Reference: + # https://github.com/openai/whisper/blob/90db0de1896c23cbfaf0c58bc2d30665f709f170/whisper/model.py#L41 + model = convert_float_to_float16(model) + return model -class WhisperEncoderDecoderInitHelper: - @staticmethod def export_onnx( - model: WhisperEncoderDecoderInit, - device: torch.device, + self, onnx_model_path: str, - use_decoder_input_ids: bool = True, + provider: str, verbose: bool = True, use_external_data_format: bool = False, - use_int32_inputs: bool = False, + use_fp16_inputs: bool = False, + use_int32_inputs: bool = True, ): - """Export decoder to ONNX + """Export encoder-decoder-init to ONNX Args: - model (WhisperEncoderDecoderInit): the model to export - device (torch.device): device of decoder object - onnx_model_path (str): onnx path + onnx_model_path (str): path to save ONNX model + provider (str): provider to use for verifying parity on ONNX model verbose (bool, optional): print verbose information. Defaults to True. use_external_data_format (bool, optional): use external data format or not. Defaults to False. + use_fp16_inputs (bool, optional): use float16 inputs for the audio_features. Defaults to False. + use_int32_inputs (bool, optional): use int32 inputs for the decoder_input_ids. Defaults to True. """ - assert isinstance(model, WhisperEncoderDecoderInit) - - inputs = WhisperEncoderDecoderInitInputs.create_dummy( - model.config, - batch_size=2, - encode_sequence_length=3000, - use_decoder_input_ids=True, - device=device, - use_int32_inputs=use_int32_inputs, - ) - input_list = inputs.to_list() - - out = model(inputs.encoder_input_ids, inputs.decoder_input_ids, remove_hooks=True) - present = out[2] - present_names = PastKeyValuesHelper.get_input_names(present, encoder=True) - - output_names = ["logits", "encoder_hidden_states", *present_names] - - # Shape of input tensors (sequence_length==1): - # input_ids: (batch_size, sequence_length) - # encoder_hidden_states: (batch_size, encode_sequence_length, hidden_size) - # past_self_*: (batch_size, num_heads, past_decode_sequence_length, head_size) - # past_cross_*: (batch_size, num_heads, encode_sequence_length, head_size) - - # Shape of output tensors: + # Shape of encoder's tensors: + # Inputs: + # audio_features: (batch_size, num_mels, num_frames) + # Outputs: + # encoder_hidden_states: (batch_size, num_frames // 2, hidden_size) + + # Shape of decoder's tensors: + # Inputs: + # decoder_input_ids: (batch_size, sequence_length) + # encoder_hidden_states (comes from encoder's outputs): (batch_size, num_frames // 2, hidden_size) + # Outputs: # logits: (batch_size, sequence_length, vocab_size) - # past_self_*: (batch_size, num_heads, past_decode_sequence_length + sequence_length, head_size) - # past_cross_*: (batch_size, num_heads, encode_sequence_length, head_size) - - input_names = ["encoder_input_ids"] - - # ONNX exporter might mark dimension like 'Transposepresent_value_self_1_dim_2' in shape inference. - # We use a workaround here: first use dim_param "1" for sequence_length, and later change to dim_value. - sequence_length = "1" - num_heads = str(model.config.encoder_attention_heads) - hidden_size = str(model.config.d_model) - head_size = str(model.config.d_model // model.config.encoder_attention_heads) - dynamic_axes = { - "encoder_input_ids": {0: "batch_size", 1: "feature_size"}, - "encoder_hidden_states": { - 0: "batch_size", - 1: "encode_sequence_length", - 2: hidden_size, - }, - "logits": { - 0: "batch_size", - 1: "decode_sequence_length", - }, - } - - if use_decoder_input_ids: - input_names.append("decoder_input_ids") - dynamic_axes["decoder_input_ids"] = { - 0: "batch_size", - 1: "decode_sequence_length", - } - - for name in present_names: - if "cross" in name: - dynamic_axes[name] = { - 0: "batch_size", - 1: num_heads, - 2: "encode_sequence_length", - 3: head_size, - } - - else: # self attention past state - dynamic_axes[name] = { - 0: "batch_size", - 1: num_heads, - 2: "decode_sequence_length", - 3: head_size, - } + # present_{key/value}_self_* (present self attention KV caches): (batch_size, num_heads, past_sequence_length + sequence_length, head_size) + # present_{key/value}_cross_* (present cross attention KV caches): (batch_size, num_heads, num_frames // 2, head_size) + + inputs = self.inputs(use_fp16_inputs=use_fp16_inputs, use_int32_inputs=use_int32_inputs) + input_names = self.input_names() + output_names = self.output_names() + dynamic_axes = self.dynamic_axes(input_names, output_names) + Path(onnx_model_path).parent.mkdir(parents=True, exist_ok=True) with tempfile.TemporaryDirectory() as tmp_dir_name: temp_onnx_model_path = os.path.join(tmp_dir_name, "encoder_decoder_init.onnx") Path(temp_onnx_model_path).parent.mkdir(parents=True, exist_ok=True) - torch_onnx_export( - model, - args=tuple(input_list), - f=temp_onnx_model_path, + out_path = temp_onnx_model_path if use_external_data_format else onnx_model_path + + torch.onnx.export( + self, + args=inputs, + f=out_path, export_params=True, input_names=input_names, output_names=output_names, dynamic_axes=dynamic_axes, opset_version=17, do_constant_folding=True, - use_external_data_format=use_external_data_format, verbose=verbose, ) - # Workaround as mentioned earlier: change numeric dim_param to dim_value - model = onnx.load(temp_onnx_model_path) - for tensor in model.graph.output: - for dim_proto in tensor.type.tensor_type.shape.dim: - if dim_proto.HasField("dim_param") and dim_proto.dim_param in [ - sequence_length, - num_heads, - hidden_size, - head_size, - ]: - dim_value = int(dim_proto.dim_param) - dim_proto.Clear() - dim_proto.dim_value = dim_value - + model = onnx.load_model(out_path, load_external_data=use_external_data_format) + model = self.fix_outputs(model) + model = self.fix_layernorm_weights(model, use_fp16_inputs) OnnxModel.save( model, onnx_model_path, @@ -232,74 +308,64 @@ def export_onnx( all_tensors_to_one_file=True, ) - @staticmethod - def onnxruntime_inference(ort_session, inputs: WhisperEncoderDecoderInitInputs): - """Run inference of ONNX model.""" - logger.debug("start onnxruntime_inference") - - ort_inputs = { - "encoder_input_ids": numpy.ascontiguousarray(inputs.encoder_input_ids.cpu().numpy()), - } - if inputs.decoder_input_ids is not None: - ort_inputs["decoder_input_ids"] = numpy.ascontiguousarray(inputs.decoder_input_ids.cpu().numpy()) + self.verify_onnx(onnx_model_path, provider, use_fp16_inputs, use_int32_inputs) - ort_outputs = ort_session.run(None, ort_inputs) - return ort_outputs - - @staticmethod def verify_onnx( - model: WhisperEncoderDecoderInit, - ort_session: InferenceSession, - device: torch.device, + self, + onnx_model_path: str, + provider: str, + use_fp16_inputs: bool, use_int32_inputs: bool, - max_cases: int = 4, ): - """Compare the result from PyTorch and OnnxRuntime to verify the ONNX model is good.""" - ort_inputs = ort_session.get_inputs() - use_decoder_input_ids = len(ort_inputs) == 3 - - test_cases = [(4, 11), (1, 2), (3, 1), (8, 5)] - test_cases_max_diff = [] - for batch_size, encode_sequence_length in test_cases[:max_cases]: - inputs = WhisperEncoderDecoderInitInputs.create_dummy( - model.config, - batch_size, - encode_sequence_length, - use_decoder_input_ids=use_decoder_input_ids, - device=device, - use_int32_inputs=use_int32_inputs, - ) - - ort_outputs = WhisperEncoderDecoderInitHelper.onnxruntime_inference(ort_session, inputs) + """Verify ONNX model outputs and PyTorch model outputs match - # Run inference of PyTorch model - input_list = inputs.to_list() - torch_outputs = model(*input_list) - - assert torch_outputs[0].cpu().numpy().shape == ort_outputs[0].shape - max_diff = numpy.amax(numpy.abs(torch_outputs[0].cpu().numpy() - ort_outputs[0])) - logger.debug(f"logits max_diff={max_diff}") - max_diff_all = max_diff - - assert torch_outputs[1].cpu().numpy().shape == ort_outputs[1].shape - max_diff = numpy.amax(numpy.abs(torch_outputs[1].cpu().numpy() - ort_outputs[1])) - logger.debug(f"encoder_hidden_states max_diff={max_diff}") - max_diff_all = max(max_diff_all, max_diff) - - for i in range(2 * model.config.num_layers): - max_diff = numpy.amax(numpy.abs(torch_outputs[2][i].cpu().numpy() - ort_outputs[2 + i])) - logger.debug(f"self attention past state {i} max_diff={max_diff}") - - for i in range(2 * model.config.num_layers): - max_diff = numpy.amax( - numpy.abs(torch_outputs[3][i].cpu().numpy() - ort_outputs[2 + 2 * model.config.num_layers + i]) - ) - logger.debug(f"cross attention past state {i} max_diff={max_diff}") - max_diff_all = max(max_diff_all, max_diff) - - test_cases_max_diff.append(max_diff_all) - logger.info( - f"batch_size={batch_size} encode_sequence_length={encode_sequence_length}, max_diff={max_diff_all}" + Args: + onnx_model_path (str): path to save ONNX model + provider (str): execution provider for ONNX model + use_fp16_inputs (bool, optional): use float16 inputs for the audio_features + use_int32_inputs (bool, optional): use int32 inputs for the decoder_input_ids + """ + # Shape of encoder's tensors: + # Inputs: + # audio_features: (batch_size, num_mels, num_frames) + # Outputs: + # encoder_hidden_states: (batch_size, num_frames // 2, hidden_size) + + # Shape of decoder's tensors: + # Inputs: + # decoder_input_ids: (batch_size, sequence_length) + # encoder_hidden_states (comes from encoder's outputs): (batch_size, num_frames // 2, hidden_size) + # Outputs: + # logits: (batch_size, sequence_length, vocab_size) + # present_{key/value}_self_* (present self attention KV caches): (batch_size, num_heads, past_sequence_length + sequence_length, head_size) + # present_{key/value}_cross_* (present cross attention KV caches): (batch_size, num_heads, num_frames // 2, head_size) + + inputs = self.inputs(use_fp16_inputs=use_fp16_inputs, use_int32_inputs=use_int32_inputs, return_dict=True) + + # Run PyTorch model + pt_outputs = [] + if self.no_beam_search_op: + out = self.forward(**inputs) + pt_outputs.append(out[0].detach().cpu().numpy()) + for present_cross_attn_cache in out[1]: + pt_outputs.append(present_cross_attn_cache.detach().cpu().numpy()) + else: + out = self.forward(**inputs) + pt_outputs.append(out[0].detach().cpu().numpy()) + pt_outputs.append(out[1].detach().cpu().numpy()) + + (self_attn_kv_caches, cross_attn_kv_caches) = group_past_key_values(out[2]) + pt_outputs.extend([self_attn_kv_cache.detach().cpu().numpy() for self_attn_kv_cache in self_attn_kv_caches]) + pt_outputs.extend( + [cross_attn_kv_cache.detach().cpu().numpy() for cross_attn_kv_cache in cross_attn_kv_caches] ) - return max(test_cases_max_diff) + # Run ONNX model + sess = InferenceSession(onnx_model_path, providers=[provider]) + ort_outputs = sess.run(None, convert_inputs_for_ort(inputs, sess)) + + # Calculate output difference + for i, output_name in enumerate(self.output_names()): + diff = np.abs(pt_outputs[i] - ort_outputs[i]) + logger.warning(f"Comparing {output_name}...") + logger.warning(f"Max diff: {np.max(diff)}") diff --git a/onnxruntime/python/tools/transformers/models/whisper/whisper_helper.py b/onnxruntime/python/tools/transformers/models/whisper/whisper_helper.py index e1206a30871d1..3cb6c23848f13 100644 --- a/onnxruntime/python/tools/transformers/models/whisper/whisper_helper.py +++ b/onnxruntime/python/tools/transformers/models/whisper/whisper_helper.py @@ -10,15 +10,13 @@ import numpy as np import torch -from float16 import float_to_float16_max_diff -from onnx_model import OnnxModel +from convert_generation import add_cache_indirection_to_mha, add_output_qk_to_mha, fix_past_sequence_length from optimizer import optimize_model -from packaging import version from transformers import WhisperConfig, WhisperForConditionalGeneration, WhisperProcessor -from transformers import __version__ as transformers_version -from whisper_decoder import WhisperDecoder, WhisperDecoderHelper, WhisperDecoderInit -from whisper_encoder import WhisperEncoder, WhisperEncoderHelper -from whisper_encoder_decoder_init import WhisperEncoderDecoderInit, WhisperEncoderDecoderInitHelper +from whisper_decoder import WhisperDecoder +from whisper_encoder import WhisperEncoder +from whisper_encoder_decoder_init import WhisperEncoderDecoderInit +from whisper_jump_times import WhisperJumpTimes from onnxruntime import InferenceSession @@ -36,6 +34,7 @@ "whisper-large", "whisper-large-v2", "whisper-large-v3", + "whisper-large-v3-turbo", ] @@ -54,7 +53,6 @@ def get_onnx_path( model_name_or_path (str): pretrained model name, or path to the model checkpoint suffix (str, optional): suffix like "_encoder" or "_decoder_fp16" will be appended to file name. Defaults to None. new_folder (bool, optional): create a new directory for the model. Defaults to False. - Returns: str: path of onnx model """ @@ -69,205 +67,132 @@ def get_onnx_path( directory = os.path.join(output_dir, model_name) if new_folder else output_dir return os.path.join(directory, model_name + ".onnx") - @staticmethod - def load_model_openai( - model_name_or_path: str, - cache_dir: str, - device: torch.device, - ) -> torch.nn.Module: - """Load model given a pretrained name or path, then build models for ONNX conversion. - - Args: - model_name_or_path (str): pretrained model name or path - cache_dir (str): cache directory - device (torch.device): device to run the model - merge_encoder_and_decoder_init (bool, optional): Whether merge encoder and decoder initialization into one ONNX model. Defaults to True. - Returns: - Dict[str, torch.nn.Module]: mapping from name to modules for ONNX conversion. - """ - from whisper import _ALIGNMENT_HEADS, _MODELS, _download - from whisper.model import ModelDimensions, Whisper - - in_memory = False - - model_name = model_name_or_path.split("/")[-1][8:] - checkpoint_file, alignment_heads = None, None - if model_name in _MODELS: - checkpoint_file = _download(_MODELS[model_name], cache_dir, in_memory) - alignment_heads = _ALIGNMENT_HEADS[model_name] - - with open(checkpoint_file, "rb") as fp: - checkpoint = torch.load(fp, map_location=device) - del checkpoint_file - - dims = ModelDimensions(**checkpoint["dims"]) - model = Whisper(dims) - model.load_state_dict(checkpoint["model_state_dict"]) - - if alignment_heads is not None: - model.set_alignment_heads(alignment_heads) - return model.to(device) - @staticmethod def load_model( model_name_or_path: str, model_impl: str, cache_dir: str, device: torch.device, + dtype: torch.dtype, merge_encoder_and_decoder_init: bool = True, + no_beam_search_op: bool = False, + output_qk: bool = False, ) -> dict[str, torch.nn.Module]: """Load model given a pretrained name or path, then build models for ONNX conversion. Args: model_name_or_path (str): pretrained model name or path + model_impl (str): library to load model from cache_dir (str): cache directory device (torch.device): device to run the model + dtype (torch.dtype): dtype to run the model merge_encoder_and_decoder_init (bool, optional): Whether merge encoder and decoder initialization into one ONNX model. Defaults to True. + no_beam_search_op (bool, optional): Whether to use beam search op or not. Defaults to False. + output_qk (bool, optional): Whether to output QKs to calculate batched jump times for word-level timestamps. Defaults to False. Returns: Dict[str, torch.nn.Module]: mapping from name to modules for ONNX conversion. """ - extra_kwargs = {} - if version.parse(transformers_version) >= version.parse("4.36.0"): - extra_kwargs["attn_implementation"] = "eager" - model = WhisperForConditionalGeneration.from_pretrained(model_name_or_path, cache_dir=cache_dir, **extra_kwargs) - - if model_impl == "openai": - openai_model = WhisperHelper.load_model_openai(model_name_or_path, cache_dir, device) - model_encoder, model_decoder = openai_model.encoder, openai_model.decoder - passed_model = openai_model + # Load PyTorch model + if model_impl == "hf": + # Load from Hugging Face + model = WhisperForConditionalGeneration.from_pretrained( + model_name_or_path, cache_dir=cache_dir, attn_implementation="eager" + ) else: - model_encoder, model_decoder = model, model - passed_model = None + # Load from OpenAI + import whisper - decoder = WhisperDecoder(model_decoder, model.config, model_impl=model_impl, model=passed_model) - decoder.eval().to(device) + if not os.path.exists(model_name_or_path): + name_or_path = model_name_or_path.split("/")[-1][8:] + else: + name_or_path = model_name_or_path + model = whisper.load_model(name_or_path, device, download_root=cache_dir, in_memory=True) + + # Set PyTorch model properties + model.eval().to(device=device) + if model_impl == "hf": + model.to(dtype=dtype) + config = WhisperConfig.from_pretrained(model_name_or_path, cache_dir=cache_dir) + # Load each component of PyTorch model + decoder = WhisperDecoder(config, model, model_impl, no_beam_search_op).eval() + components = {"decoder": decoder} if merge_encoder_and_decoder_init: - encoder_decoder_init = WhisperEncoderDecoderInit( - model_encoder, - model_decoder, - model.config, - decoder_start_token_id=None, - model_impl=model_impl, - model=passed_model, - ) - return {"encoder_decoder_init": encoder_decoder_init, "decoder": decoder} + encoder_decoder_init = WhisperEncoderDecoderInit(config, model, model_impl, no_beam_search_op).eval() + components.update({"encoder": encoder_decoder_init}) else: - encoder = WhisperEncoder(model.model.encoder, model.config) - encoder.eval().to(device) - decoder_init = WhisperDecoderInit(model.decoder, model.config) - decoder_init.eval().to(device) - return { - "encoder": encoder, - "decoder": decoder, - "decoder_init": decoder_init, - } + encoder = WhisperEncoder(config, model, model_impl).eval() + components.update({"encoder": encoder, "decoder_init": decoder}) + + if output_qk: + batched_jump_times = WhisperJumpTimes(config, device, cache_dir).eval() + components.update({"jump_times": batched_jump_times}) + return components @staticmethod def export_onnx( - model: WhisperEncoder | WhisperDecoder | WhisperDecoderInit | WhisperEncoderDecoderInit, - device: torch.device, + model: WhisperEncoder | WhisperEncoderDecoderInit | WhisperDecoder, onnx_model_path: str, - verbose: bool = True, - use_external_data_format: bool = False, - use_decoder_input_ids: bool = True, - use_int32_inputs: bool = False, + provider: str, + verbose: bool, + use_external_data_format: bool, + use_fp16_inputs: bool, + use_int32_inputs: bool, + use_encoder_hidden_states: bool, + use_kv_cache_inputs: bool, ): + """Export model component to ONNX + + Args: + model (class): PyTorch class to export + onnx_model_path (str): path to save ONNX model + provider (str): provider to use for verifying parity on ONNX model + verbose (bool): print verbose information. + use_external_data_format (bool): use external data format or not. + use_fp16_inputs (bool): use float16 inputs for the audio_features, encoder_hidden_states, logits, and KV caches. + use_int32_inputs (bool): use int32 inputs for the decoder_input_ids. + use_encoder_hidden_states (bool): use encoder_hidden_states as model input for decoder-init/decoder-without-past models. + use_kv_cache_inputs (bool): use KV caches as model inputs for decoder-with-past models. + """ if isinstance(model, WhisperEncoder): - WhisperEncoderHelper.export_onnx( - model, - device, + model.export_onnx( onnx_model_path, + provider, verbose, use_external_data_format, + use_fp16_inputs, ) elif isinstance(model, WhisperEncoderDecoderInit): - WhisperEncoderDecoderInitHelper.export_onnx( - model, - device, + model.export_onnx( onnx_model_path, - use_decoder_input_ids, + provider, verbose, use_external_data_format, + use_fp16_inputs, use_int32_inputs, ) - else: - WhisperDecoderHelper.export_onnx( - model, - device, + elif isinstance(model, WhisperDecoder): + model.export_onnx( onnx_model_path, + provider, verbose, use_external_data_format, + use_fp16_inputs, + use_int32_inputs, + use_encoder_hidden_states, + use_kv_cache_inputs, + ) + elif isinstance(model, WhisperJumpTimes): + model.export_onnx( + onnx_model_path, + provider, + verbose, + use_external_data_format, + use_fp16_inputs, use_int32_inputs, ) - - @staticmethod - def auto_mixed_precision( - onnx_model: OnnxModel, - op_block_list: tuple[str] = ( - "SimplifiedLayerNormalization", - "SkipSimplifiedLayerNormalization", - "Relu", - "Add", - ), - ): - """Convert model to mixed precision. - It detects whether original model has fp16 precision weights, and set parameters for float16 conversion automatically. - Args: - onnx_model (OnnxModel): optimized ONNX model - op_block_list (List[str], optional): . Defaults to ["SimplifiedLayerNormalization", "SkipSimplifiedLayerNormalization", "Relu", "Add"] - Returns: - parameters(dict): a dictionary of parameters used in float16 conversion - """ - op_full_set = {node.op_type for node in onnx_model.nodes()} - fp32_op_set = set(op_block_list) - fp16_op_set = op_full_set.difference(fp32_op_set) - logger.info(f"fp32 op: {fp32_op_set} fp16 op: {fp16_op_set}") - - # logits is the first output - logits_output_name = onnx_model.graph().output[0].name - - # We use the weight in last MatMul node to detect whether the model is stored with float16 weights from training. - is_weight_fp16_precision = False - output_name_to_node = onnx_model.output_name_to_node() - assert logits_output_name in output_name_to_node - node = output_name_to_node[logits_output_name] - last_matmul_node = None - if node.op_type == "MatMul": - last_matmul_node = node - logger.info(f"Found last MatMul node for logits: {node.name}") - initializer = None - for input in node.input: - initializer = onnx_model.get_initializer(input) - if initializer is not None: - break - - # when the max difference of value after converting float to float16 is lower than a threshold (1e-6), - # we can deduce that the weights are stored in float16 precision. - max_diff = float_to_float16_max_diff(initializer) - logger.debug(f"max diff of converting weights in last MatMul node {node.name}: {max_diff}") - is_weight_fp16_precision = max_diff < 1e-6 else: - logger.warning(f"Failed to find MatMul node for logits. Found {node.op_type} of node {node.name}") - - keep_io_types = [] - node_block_list = [] - if (not is_weight_fp16_precision) and (last_matmul_node is not None): - # When original weight is float32 precision, keep logits and last MatMul in float32 could get better precision. - keep_io_types = [logits_output_name] - node_block_list = [last_matmul_node.name] - - parameters = { - "keep_io_types": keep_io_types, - "op_block_list": list(op_block_list), - "node_block_list": node_block_list, - "force_fp16_initializers": is_weight_fp16_precision, - } - - logger.info(f"auto_mixed_precision parameters: {parameters}") - onnx_model.convert_float_to_float16(use_symbolic_shape_infer=True, **parameters) - - return parameters + raise ValueError(f"Unknown instance for model detected: {type(model)}") @staticmethod def optimize_onnx( @@ -276,10 +201,13 @@ def optimize_onnx( is_float16: bool, num_attention_heads: int, hidden_size: int, + num_layers: int, use_external_data_format: bool = False, - auto_mixed_precision: bool = True, use_gpu: bool = False, provider: str = "cpu", + is_decoder: bool = False, + no_beam_search_op: bool = False, + output_qk: bool = False, ): """Optimize ONNX model with an option to convert it to use mixed precision.""" @@ -294,17 +222,23 @@ def optimize_onnx( model_type="bart", num_heads=num_attention_heads, hidden_size=hidden_size, - opt_level=2 if not use_external_data_format else None, + opt_level=0, optimization_options=optimization_options, use_gpu=use_gpu, only_onnxruntime=False, ) - if is_float16: - if auto_mixed_precision: - WhisperHelper.auto_mixed_precision(m) - else: - m.convert_model_float32_to_float16(cast_input_output=False) + # Add `past_sequence_length`, `cache_indirection`, and `output_qk` to `MultiHeadAttention` ops + if is_decoder and no_beam_search_op: + if provider == "cuda": # FP32 CPU can be supported here once the DMMHA CPU kernel bugs are fixed + # FP16 CUDA, FP32 CUDA, and FP32 CPU use the `DecoderMaskedMultiHeadAttention` kernel + # via `MultiHeadAttention`, which requires the `past_sequence_length` and + # `cache_indirection` inputs + m, past_seq_len_name = fix_past_sequence_length(m) + m = add_cache_indirection_to_mha(m, past_seq_len_name) + + if output_qk: + m = add_output_qk_to_mha(m, skip_node_idxs=list(range(0, 2 * num_layers, 2))) m.save_model_to_file(optimized_model_path, use_external_data_format, all_tensors_to_one_file=True) @@ -362,7 +296,7 @@ def pt_transcription_for_verify_onnx( # https://huggingface.co/docs/transformers/model_doc/whisper#transformers.WhisperForConditionalGeneration.generate.prompt_ids # prompt_ids input requires a tensor of rank 1 for i in range(batch_size): - inputs["prompt_ids"] = torch.from_numpy(prompt_ids[i]) + inputs["prompt_ids"] = torch.from_numpy(prompt_ids[i]).to(device=device) inputs["input_features"] = input_features_[i].to(device) pt_output = pt_model.generate(**inputs).detach().cpu().numpy() pt_outputs.append(pt_output) @@ -411,6 +345,33 @@ def select_transcription_options( } return expected_transcription_options + @staticmethod + def get_outputs( + pt_outputs: np.ndarray, + ort_outputs: np.ndarray, + i: int, + ): + """Get PyTorch and ONNX Runtime output token ids at index i""" + pt_output, ort_output = pt_outputs[i], ort_outputs[i] + pt_shape, ort_shape = pt_output.shape, ort_output.shape + + # Hugging Face impl. + Beam Search op: PyTorch = (26,) and ORT = (30,) + # OpenAI impl. + Beam Search op: PyTorch = (1, 30) and ORT = (30,) + if pt_shape != ort_shape: + if len(pt_shape) > 1: + pt_output = pt_output[0] + pt_shape = pt_output.shape + if len(ort_shape) > 1: + ort_output = ort_output[0] + ort_shape = ort_output.shape + if pt_shape[0] != ort_shape[0]: + min_len = min(pt_shape[0], ort_shape[0]) + pt_output = pt_output[:min_len] + ort_output = ort_output[:min_len] + + assert pt_output.shape == ort_output.shape + return pt_output, ort_output + @staticmethod def verify_onnx( model_name_or_path: str, @@ -421,11 +382,8 @@ def verify_onnx( prompt_mode: bool = False, ): """Compare the result from PyTorch and ONNX Runtime to verify the ONNX model is good.""" - extra_kwargs = {} - if version.parse(transformers_version) >= version.parse("4.36.0"): - extra_kwargs["attn_implementation"] = "eager" pt_model = WhisperForConditionalGeneration.from_pretrained( - model_name_or_path, cache_dir=cache_dir, **extra_kwargs + model_name_or_path, cache_dir=cache_dir, attn_implementation="eager" ).to(device) processor = WhisperProcessor.from_pretrained(model_name_or_path, cache_dir=cache_dir) config = WhisperConfig.from_pretrained(model_name_or_path, cache_dir=cache_dir) @@ -491,12 +449,19 @@ def verify_onnx( inputs[name] = np.array([1.0], dtype=ort_to_np[dtype]) else: inputs[name] = np.array([inputs[name]], dtype=ort_to_np[dtype]) + ort_outputs = ort_session.run(None, inputs)[0][:, 0, :] ort_transcription = processor.batch_decode(ort_outputs, skip_special_tokens=True) expected_transcription_options = WhisperHelper.select_transcription_options(batch_size, prompt_mode) parity = 1 for i in range(batch_size): + pt_output, ort_output = WhisperHelper.get_outputs(pt_outputs, ort_outputs, i) + + # Check if token ids match + parity *= np.allclose(pt_output, ort_output) + + # Check if transcribed outputs match parity *= ( pt_transcription[i] in expected_transcription_options and ort_transcription[i] in expected_transcription_options @@ -505,10 +470,9 @@ def verify_onnx( if not parity: for i in range(batch_size): - if pt_outputs[i].shape != ort_outputs[i].shape: - diff = pt_outputs[i] - ort_outputs[i][:, : len(pt_outputs[i])] - else: - diff = pt_outputs[i] - ort_outputs[i] + pt_output, ort_output = WhisperHelper.get_outputs(pt_outputs, ort_outputs, i) + diff = pt_output - ort_output + max_diff_i = max(diff.min(), diff.max(), key=abs) max_diff = max(max_diff, max_diff_i) @@ -516,4 +480,4 @@ def verify_onnx( logger.warning(f"PyTorch outputs: {pt_transcription}") logger.warning(f"ONNX Runtime outputs: {ort_transcription}") - return max_diff + return 0 diff --git a/onnxruntime/python/tools/transformers/models/whisper/whisper_inputs.py b/onnxruntime/python/tools/transformers/models/whisper/whisper_inputs.py new file mode 100644 index 0000000000000..0b0882eface72 --- /dev/null +++ b/onnxruntime/python/tools/transformers/models/whisper/whisper_inputs.py @@ -0,0 +1,380 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +import logging + +import numpy as np +import torch +from transformers import WhisperConfig + +from onnxruntime import InferenceSession + +logger = logging.getLogger(__name__) + + +# Create audio_features for encoder +# Shape is (batch_size, feature_size, sequence_length) = (batch_size, num_mel_filters, num_frames) +# where num_mel_filters is a model attribute and num_frames = (chunk_length * sample_rate) // hop_length. +# +# Hard-coded audio hyperparameters: +# SAMPLE_RATE = 16000 +# N_FFT = 400 +# HOP_LENGTH = 160 +# CHUNK_LENGTH = 30 (i.e. 30-second chunk of audio) +# N_SAMPLES = CHUNK_LENGTH * SAMPLE_RATE = 30 * 16000 = 480000 (i.e. 480,000 samples in a 30-second chunk of audio) +# N_FRAMES = N_SAMPLES // HOP_LENGTH = 480000 // 160 = 3000 (i.e. 3000 frames in a mel spectrogram input) +# +# N_SAMPLES_PER_TOKEN = HOP_LENGTH * 2 = 160 * 2 = 320 +# FRAMES_PER_TOKEN = SAMPLE_RATE // HOP_LENGTH = 16000 // 160 = 100 (i.e. 10 ms per audio frame) +# TOKENS_PER_SECOND = SAMPLE_RATE // N_SAMPLES_PER_TOKEN = 16000 // 320 = 50 (i.e. 20 ms per audio token) +def get_sample_audio_features( + config: WhisperConfig, + device: torch.device, + batch_size: int, + sequence_length: int = 3000, + use_fp16: bool = False, +): + torch_dtype = torch.float16 if use_fp16 else torch.float32 + audio_features = torch.randn(batch_size, config.num_mel_bins, sequence_length, device=device, dtype=torch_dtype) + return audio_features + + +# Create input_ids for decoder +# Shape is (batch_size, sequence_length) where sequence_length is the initial decoder sequence length +def get_sample_decoder_input_ids( + config: WhisperConfig, + device: torch.device, + batch_size: int, + sequence_length: int, + use_int32: bool = True, +): + torch_dtype = torch.int32 if use_int32 else torch.int64 + decoder_input_ids = torch.randint( + low=0, high=config.vocab_size, size=(batch_size, sequence_length), device=device, dtype=torch_dtype + ) + return decoder_input_ids + + +# Create encoder_hidden_states for decoder-init +# Shape is (batch_size, num_frames // 2, hidden_size) +def get_sample_encoder_hidden_states( + config: WhisperConfig, + device: torch.device, + batch_size: int, + use_fp16: bool = False, +): + torch_dtype = torch.float16 if use_fp16 else torch.float32 + encoder_hidden_states = torch.randn( + batch_size, config.max_source_positions, config.d_model, device=device, dtype=torch_dtype + ) + return encoder_hidden_states + + +# Create past_key_values +# Self-attention KV caches are of shape (batch_size, num_heads, past_sequence_length, head_size) +# Cross-attention KV caches are of shape (batch_size, num_heads, num_frames // 2, head_size) +def get_sample_past_key_values( + config: WhisperConfig, + device: torch.device, + batch_size: int, + past_seq_len: int, + use_fp16: bool = False, +): + num_heads = config.decoder_attention_heads + head_size = config.d_model // num_heads + max_source_positions = ( + config.max_source_positions + ) # equal to num_frames // 2 = encoder's sequence_length // 2 = 3000 // 2 = 1500 + torch_dtype = torch.float16 if use_fp16 else torch.float32 + self_attention_kv_caches = [ + ( + torch.rand(batch_size, num_heads, past_seq_len, head_size, device=device, dtype=torch_dtype), + torch.rand(batch_size, num_heads, past_seq_len, head_size, device=device, dtype=torch_dtype), + ) + for _ in range(config.num_hidden_layers) + ] + cross_attention_kv_caches = [ + ( + torch.rand(batch_size, num_heads, max_source_positions, head_size, device=device, dtype=torch_dtype), + torch.rand(batch_size, num_heads, max_source_positions, head_size, device=device, dtype=torch_dtype), + ) + for _ in range(config.num_hidden_layers) + ] + return flatten_past_key_values(self_attention_kv_caches, cross_attention_kv_caches) + + +# Flatten KV caches into pairs-of-4 where each pair is defined as: +# (self_attn_key_cache, self_attn_value_cache, cross_attn_key_cache, cross_attn_value_cache) +def flatten_past_key_values( + self_attn_kv_caches: list[tuple[torch.Tensor, torch.Tensor]], + cross_attn_kv_caches: list[tuple[torch.Tensor, torch.Tensor]], +): + past_key_values = [] + for (self_k_cache, self_v_cache), (cross_k_cache, cross_v_cache) in zip( + self_attn_kv_caches, cross_attn_kv_caches, strict=False + ): + layer_kv_caches = (self_k_cache, self_v_cache, cross_k_cache, cross_v_cache) + past_key_values.append(layer_kv_caches) + return past_key_values + + +# Group KV caches into two 1D lists where one list contains the self attention KV caches and +# one list contains the cross attention KV caches +def group_past_key_values( + kv_caches: list[tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]], +): + self_attn_kv_caches, cross_attn_kv_caches = [], [] + for self_k_cache, self_v_cache, cross_k_cache, cross_v_cache in kv_caches: + self_attn_kv_caches.append(self_k_cache) + self_attn_kv_caches.append(self_v_cache) + cross_attn_kv_caches.append(cross_k_cache) + cross_attn_kv_caches.append(cross_v_cache) + return self_attn_kv_caches, cross_attn_kv_caches + + +# Create alignment heads for timestamps +# Shape is (num_alignment_heads, 2) +def get_sample_alignment_heads( + config: WhisperConfig, + device: torch.device, + num_alignment_heads: int = 6, + use_int32: bool = True, +): + torch_dtype = torch.int32 if use_int32 else torch.int64 + alignment_heads = torch.ones((num_alignment_heads, 2), device=device, dtype=torch_dtype) + return alignment_heads + + +# Create length of start-of-transcription sequence for timestamps +# Shape is (1) +def get_sample_sot_sequence_length( + device: torch.device, + sot_sequence_length: int, + use_int32: bool = False, +): + torch_dtype = torch.int32 if use_int32 else torch.int64 + sot_length = torch.tensor([sot_sequence_length], device=device, dtype=torch_dtype) + return sot_length + + +# Create segment length for timestamps +# Shape is (1) +def get_sample_segment_length( + device: torch.device, + segment_length: int, + use_int32: bool = False, +): + torch_dtype = torch.int32 if use_int32 else torch.int64 + segment_size = torch.tensor([segment_length], device=device, dtype=torch_dtype) + return segment_size + + +# Create QKs for timestamps +# Shape is (batch_size, num_heads, sequence_length, num_frames // 2) +def get_sample_QKs( # noqa: N802 + config: WhisperConfig, + device: torch.device, + batch_size: int, + sequence_length: int, + use_fp16: bool = False, +): + num_heads = config.decoder_attention_heads + torch_dtype = torch.float16 if use_fp16 else torch.float32 + QKs = [ # noqa: N806 + torch.rand( + batch_size, num_heads, sequence_length, config.max_source_positions, device=device, dtype=torch_dtype + ) + for _ in range(config.num_hidden_layers) + ] + return QKs + + +# Create inputs for encoder component of Whisper +def get_sample_encoder_inputs( + config: WhisperConfig, + device: torch.device, + batch_size: int, + sequence_length: int = 3000, + use_fp16: bool = False, +): + audio_features = get_sample_audio_features(config, device, batch_size, sequence_length, use_fp16) + return {"audio_features": audio_features} + + +# Create inputs for encoder component + first pass through decoder component of Whisper +def get_sample_encoder_decoder_init_inputs( + config: WhisperConfig, + device: torch.device, + batch_size: int, + decoder_sequence_length: int, + encoder_sequence_length: int = 3000, + use_fp16: bool = False, + use_int32: bool = True, +): + audio_features = get_sample_audio_features(config, device, batch_size, encoder_sequence_length, use_fp16) + decoder_input_ids = get_sample_decoder_input_ids(config, device, batch_size, decoder_sequence_length, use_int32) + return {"audio_features": audio_features, "decoder_input_ids": decoder_input_ids} + + +# Create inputs for decoder component of Whisper +# Inputs for first pass through the decoder (i.e. decoder-init): decoder_input_ids, encoder_hidden_states +# Inputs for subsequent passes through the decoder (i.e. decoder-with-past): decoder_input_ids, past_key_values +def get_sample_decoder_inputs( + config: WhisperConfig, + device: torch.device, + batch_size: int, + past_sequence_length: int, + sequence_length: int, + use_fp16: bool = False, + use_int32: bool = True, +): + decoder_input_ids = get_sample_decoder_input_ids(config, device, batch_size, sequence_length, use_int32) + encoder_hidden_states = get_sample_encoder_hidden_states(config, device, batch_size, use_fp16) + past_key_values = get_sample_past_key_values(config, device, batch_size, past_sequence_length, use_fp16) + return { + "decoder_input_ids": decoder_input_ids, + "encoder_hidden_states": encoder_hidden_states, + "past_key_values": past_key_values, + } + + +# Create inputs for timestamps component of Whisper +def get_sample_jump_times_inputs( + config: WhisperConfig, + device: torch.device, + batch_size: int, + sequence_length: int, + num_alignment_heads: int, + sot_sequence_length: int, + segment_length: int, + use_fp16: bool = False, + use_int32: bool = True, +): + alignment_heads = get_sample_alignment_heads(config, device, num_alignment_heads, use_int32) + # lengths need to be int64 because subsequent 'Slice' ops only take int64 inputs + sot_sequence_length = get_sample_sot_sequence_length(device, sot_sequence_length) + segment_length = get_sample_segment_length(device, segment_length) + QKs = get_sample_QKs(config, device, batch_size, sequence_length, use_fp16) # noqa: N806 + return { + "alignment_heads": alignment_heads, + "sot_sequence_length": sot_sequence_length, + "segment_length": segment_length, + "QKs": QKs, + } + + +# Convert PyTorch inputs to ONNX Runtime inputs +def convert_inputs_for_ort( + inputs: dict, + model: InferenceSession, +): + self_attn_kv_caches, cross_attn_kv_caches = None, None + batch_size, num_heads, past_seq_len, head_size = 0, 0, 0, 0 + num_beams, max_seq_len = 1, 448 + if "past_key_values" in inputs: + (self_attn_kv_caches, cross_attn_kv_caches) = group_past_key_values(inputs["past_key_values"]) + batch_size, num_heads, past_seq_len, head_size = self_attn_kv_caches[0].shape + + ort_inputs = {} + model_inputs = list(map(lambda i: i.name, model.get_inputs())) # noqa: C417 + use_buffer_sharing = "cache_indirection" in model_inputs + for name in model_inputs: + if name in {"audio_features", "encoder_input_ids"}: + # Encoder input + ort_inputs[name] = inputs["audio_features"].detach().cpu().numpy() + elif name == "encoder_hidden_states": + # Encoder output + ort_inputs[name] = inputs["encoder_hidden_states"].detach().cpu().numpy() + elif name in {"decoder_input_ids", "input_ids"}: + # Decoder input + ort_inputs[name] = inputs["decoder_input_ids"].detach().cpu().numpy() + elif "past_key_self" in name or "past_value_self" in name: + # Decoder input + orig_kv_cache = self_attn_kv_caches.pop(0).detach().cpu().numpy() + if use_buffer_sharing: + new_kv_cache = np.zeros((batch_size, num_heads, max_seq_len, head_size), dtype=orig_kv_cache.dtype) + new_kv_cache[:batch_size, :num_heads, :past_seq_len, :head_size] = orig_kv_cache + ort_inputs[name] = new_kv_cache + else: + ort_inputs[name] = orig_kv_cache + elif "past_key_cross" in name or "past_value_cross" in name: + # Decoder input + orig_kv_cache = cross_attn_kv_caches.pop(0).detach().cpu().numpy() + ort_inputs[name] = orig_kv_cache + elif name == "past_sequence_length": + # Decoder input + ort_inputs[name] = np.array([past_seq_len], dtype=np.int32) + elif name == "cache_indirection": + # Decoder input + ort_inputs[name] = np.zeros((batch_size, num_beams, max_seq_len), dtype=np.int32) + elif name == "alignment_heads": + # Jump times input + ort_inputs[name] = inputs["alignment_heads"].detach().cpu().numpy() + elif name == "sot_sequence_length": + # Jump times input + ort_inputs[name] = inputs["sot_sequence_length"].detach().cpu().numpy() + elif name == "segment_length": + # Jump times input + ort_inputs[name] = inputs["segment_length"].detach().cpu().numpy() + elif "cross_qk" in name: + # Jump times input + ort_inputs[name] = inputs["QKs"].pop(0).detach().cpu().numpy() + else: + raise ValueError(f"Unknown name not recognized: {name}") + + return ort_inputs + + +# Get dynamic axes for all inputs and outputs to the model +def get_model_dynamic_axes( + config: WhisperConfig, + input_names: list[str], + output_names: list[str], +): + dynamic_axes = {} + for name in input_names + output_names: + if name in {"audio_features", "encoder_input_ids"}: + # shape is (batch_size, num_mels, num_frames) + dynamic_axes[name] = {0: "batch_size"} + elif name in {"input_ids", "decoder_input_ids"}: + # shape is (batch_size, sequence_length) + dynamic_axes[name] = {0: "batch_size", 1: "sequence_length"} + elif name == "alignment_heads": + # shape is (num_alignment_heads, 2) + dynamic_axes[name] = {0: "num_alignment_heads"} + elif name in {"sot_sequence_length", "segment_length"}: + # shape is (1) + pass + elif name == "logits": + # shape is (batch_size, sequence_length, vocab_size) + dynamic_axes[name] = {0: "batch_size", 1: "sequence_length"} + elif name == "encoder_hidden_states": + # shape is (batch_size, num_frames // 2, hidden_size) + dynamic_axes[name] = {0: "batch_size"} + elif "past_key_self" in name or "past_value_self" in name: + # shape is (batch_size, num_heads, past_sequence_length, head_size) + dynamic_axes[name] = {0: "batch_size", 2: "past_sequence_length"} + elif "present_key_self" in name or "present_value_self" in name: + # shape is (batch_size, num_heads, past_sequence_length + sequence_length, head_size), + # which is equal to (batch_size, num_heads, total_sequence_length, head_size) + dynamic_axes[name] = {0: "batch_size", 2: "total_sequence_length"} + elif ( + "past_key_cross" in name + or "past_value_cross" in name + or "present_key_cross" in name + or "present_value_cross" in name + ): + # shape is (batch_size, num_heads, num_frames // 2, head_size) + dynamic_axes[name] = {0: "batch_size"} + elif "cross_qk" in name: + # shape is (batch_size, num_heads, source_sequence_length, target_sequence_length) + dynamic_axes[name] = {0: "batch_size", 2: "sequence_length"} + elif "jump_times" in name: + # shape is (batch_size, max_length) + dynamic_axes[name] = {0: "batch_size", 1: "max_length"} + else: + raise Exception(f"Unknown input or output name found: {name}") + return dynamic_axes diff --git a/onnxruntime/python/tools/transformers/models/whisper/whisper_jump_times.py b/onnxruntime/python/tools/transformers/models/whisper/whisper_jump_times.py new file mode 100644 index 0000000000000..4765616ec2b6f --- /dev/null +++ b/onnxruntime/python/tools/transformers/models/whisper/whisper_jump_times.py @@ -0,0 +1,477 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +import logging +import os +import tempfile +import textwrap +from pathlib import Path + +import numpy as np +import onnx +import torch +import torch.nn.functional as F +import torch.utils.cpp_extension +from onnx_model import OnnxModel +from transformers import WhisperConfig +from whisper_inputs import convert_inputs_for_ort, get_model_dynamic_axes, get_sample_jump_times_inputs + +from onnxruntime import InferenceSession +from onnxruntime.tools import pytorch_export_contrib_ops + +logger = logging.getLogger(__name__) + +################################################## +# Functions that have to be outside of the class +# for torch.jit.script_if_tracing to work +################################################## + + +@torch.jit.script_if_tracing +def index_QKs(alignment_heads: torch.Tensor, QKs: list[torch.Tensor]): # noqa: N802 + """ + Compute the following to get stacked QK tensor that has been indexed for the desired attention heads: + weights = torch.stack([QKs[_l][:, _h] for _l, _h in alignment_heads], dim=1) + """ + indexed_QKs = [] # noqa: N806 + for pair in alignment_heads: + # Each QK is of shape (batch_size, num_heads, sequence_length, num_frames // 2) + # The `QKs[_l]` selects the right QK from the list of QKs + # The `QKs[_l][:, _h]` selects the right attention heads from the chosen QK. The `:` is to do this for the batch dim. + # + # PyTorch: + # QKs[_l] is of shape (batch_size, num_heads, sequence_length, num_frames // 2) + # QKs[_l][:, _h] is of shape (batch_size, sequence_length, num_frames // 2) + # + # ONNX: + # QKs[_l] is of shape (batch_size, num_heads, sequence_length, num_frames // 2) + # QKs[_l][:, _h] is of shape (batch_size, 1, sequence_length, num_frames // 2) because + # the `[:, _h]` operation maps to a Gather op and that op does not reduce dimensions + _l, _h = pair[0], pair[1] + indexed_QKs.append(QKs[_l][:, _h]) + + # PyTorch: + # torch.stack will return a tensor of shape (batch_size, num_alignment_heads, sequence_length, num_frames // 2). + # + # ONNX: + # torch.stack will return a tensor of shape (batch_size, num_alignment_heads, 1, sequence_length, num_frames // 2) + # because the Gather op does not reduce dimensions. To remove the unneeded dimension, torch.squeeze with a specified + # dim (dim = 2) is added. The torch.squeeze op with a specified dim only runs if the specified dim has a size of 1. + # Since the dim won't be of size 1 in the PyTorch tensor but it is of size 1 in the ONNX tensor, it will be a no-op + # in PyTorch and an op in ONNX. Thus, the Squeeze op will only affect the ONNX model. + weights = torch.stack(indexed_QKs, dim=1) + weights = torch.squeeze(weights, dim=2) + return weights + + +def jump_timings(text_indices, time_indices): + """ + Calculate jump times from text_indices and time_indices where + text_indices and time_indices are both 1d vectors + """ + TOKENS_PER_SECOND = 50.0 # noqa: N806 + diff = text_indices[1:] - text_indices[:-1] + padding = torch.tensor([1], dtype=torch.int32) + jumps = torch.cat((padding, diff)).to(torch.bool) + jump_times = time_indices[jumps].to(torch.float) / TOKENS_PER_SECOND + return jump_times + + +def padded_jump_from_dtw(matrix_2d: torch.Tensor, max_length: torch.Tensor): + """ + Run Dynamic Time Warping (DTW) on batched tensor + """ + trace = torch.ops.onnxruntime.DynamicTimeWarping(matrix_2d) + text_indices = trace[0, :] + time_indices = trace[1, :] + jump_times = jump_timings(text_indices, time_indices) + return F.pad(jump_times, [0, int((max_length - jump_times.size(-1)).item())], mode="constant", value=-1.0) + + +@torch.jit.script_if_tracing +def batch_jump_times(matrix: torch.Tensor, max_decoded_length: torch.Tensor): + """ + Compute the following to calculate jump times for all batches: + batched_jump_times = torch.stack([self.padded_jump_from_dtw(matrix[b], max_decoded_length) for b in range(matrix.size(0))]) + """ + list_of_jump_times = [] + for b in range(matrix.size(0)): + jump_times = padded_jump_from_dtw(matrix[b], max_decoded_length) + list_of_jump_times.append(jump_times) + batched_jump_times = torch.stack(list_of_jump_times) + return batched_jump_times + + +class WhisperJumpTimes(torch.nn.Module): + """Whisper jump times component""" + + def __init__(self, config: WhisperConfig, device: torch.device, cache_dir: str | os.PathLike): + super().__init__() + self.config = config + self.device = device + self.cache_dir = cache_dir + + self.filter_width = 7 + self.qk_scale = 1.0 + + def median_filter(self, weights: torch.Tensor): + """ + Apply a median filter of width `filter_width` along the last dimension of `weights` + """ + pad_width = self.filter_width // 2 + x = F.pad(weights, (pad_width, pad_width, 0, 0), mode="reflect") + x_unfolded = torch.ops.onnxruntime.UnfoldTensor(x, -1, self.filter_width, 1) + result = torch.select(x_unfolded.sort()[0], dim=-1, index=pad_width) + return result + + def forward( + self, + alignment_heads: torch.Tensor, + sot_sequence_length: torch.Tensor, + segment_length: torch.Tensor, + QKs: list[torch.Tensor], + ): + # Get stacked QKs tensor + weights = index_QKs(alignment_heads, QKs) + weights = weights[:, :, : segment_length // 2] + weights = weights.to(torch.float32) + + weights = (weights * self.qk_scale).softmax(dim=-1) + std, mean = torch.std_mean(weights, dim=-2, keepdim=True, unbiased=False) + weights = (weights - mean) / std + weights = self.median_filter(weights) + + matrix = torch.mean(weights, 1) + matrix = -matrix[:, sot_sequence_length:-1] + + max_decoded_length = torch.tensor([matrix.size(1)], dtype=torch.int64) + batched_jump_times = batch_jump_times(matrix, max_decoded_length) + return batched_jump_times + + def input_names(self): + input_names = [ + "alignment_heads", + "sot_sequence_length", + "segment_length", + *[f"cross_qk_{i}" for i in range(self.config.num_hidden_layers)], + ] + return input_names + + def output_names(self): + output_names = ["jump_times"] + return output_names + + def inputs(self, use_fp16_inputs: bool, use_int32_inputs: bool, return_dict: bool = False): + inputs = get_sample_jump_times_inputs( + self.config, + self.device, + batch_size=2, + sequence_length=8, + num_alignment_heads=6, + sot_sequence_length=3, + segment_length=1332, + use_fp16=use_fp16_inputs, + use_int32=use_int32_inputs, + ) + if return_dict: + return inputs + return ( + inputs["alignment_heads"], + inputs["sot_sequence_length"], + inputs["segment_length"], + inputs["QKs"], + ) + + def create_torch_ops(self): + """ + 1) Create UnfoldTensor and DynamicTimeWarping as torch ops + 3) Provide a symbolic mapping from torch ops to ORT contrib ops + + See https://pytorch.org/tutorials/advanced/torch_script_custom_ops.html#building-with-jit-compilation + for more details on how this works. + """ + # Set torch extensions directory to cache directory + os.environ["TORCH_EXTENSIONS_DIR"] = self.cache_dir + + # Try to import `jinja` pip package + try: + assert torch.utils.cpp_extension.verify_ninja_availability() + except Exception as e: + logger.error(f"An error occurred while verifying `ninja` is available: {e}", exc_info=True) # noqa: G201 + install_cmd = "pip install ninja" + logger.warning(f"Could not import `ninja`. Attempting to install `ninja` via `{install_cmd}`.") + os.system(install_cmd) + + # Create UnfoldTensor torch op + unfold_op_source = textwrap.dedent("""\ + #include "torch/script.h" + + torch::Tensor UnfoldTensor(torch::Tensor input, int64_t dim, int64_t size, int64_t step) { + return input.unfold(dim, size, step); + } + + // namespace is onnxruntime + static auto registry = torch::RegisterOperators("onnxruntime::UnfoldTensor", &UnfoldTensor); + """) + + torch.utils.cpp_extension.load_inline( + name="UnfoldTensor", + cpp_sources=unfold_op_source, + is_python_module=False, + verbose=True, + ) + + # Create DynamicTimeWarping torch op + dtw_op_source = textwrap.dedent("""\ + #include "torch/script.h" + #include "torch/torch.h" + #include + #include + #include + + torch::Tensor Backtrace(torch::Tensor trace) { + int64_t i = trace.size(0) - 1; + int64_t j = trace.size(1) - 1; + trace.index({0, torch::indexing::Slice()}) = 2; + trace.index({torch::indexing::Slice(), 0}) = 1; + + std::vector result_vec; + while (i > 0 || j > 0) { + result_vec.push_back(static_cast(i - 1)); + result_vec.push_back(static_cast(j - 1)); + int value = trace[i][j].item(); + + if (value == 0) { + i--; + j--; + } else if (value == 1) { + i--; + } else if (value == 2) { + j--; + } else { + throw std::runtime_error("Unexpected trace[i, j]"); + } + } + + // Compute result[::-1, :].T + torch::Tensor result = torch::from_blob(result_vec.data(), {static_cast(result_vec.size() / 2), 2}, torch::kInt32).clone(); + torch::Tensor reversed = result.flip(0); // result[::-1, :] + torch::Tensor transposed = reversed.transpose(0, 1); // .T + return transposed; + } + + torch::Tensor DynamicTimeWarping(torch::Tensor x) { + int64_t N = x.size(0); + int64_t M = x.size(1); + torch::Tensor cost = torch::full({N + 1, M + 1}, std::numeric_limits::infinity(), torch::dtype(torch::kFloat32)); + torch::Tensor trace = torch::full({N + 1, M + 1}, -1, torch::dtype(torch::kFloat32)); + + cost[0][0] = 0; + for (int j = 1; j < M + 1; j++) { + for (int i = 1; i < N + 1; i++) { + float c0 = cost[i - 1][j - 1].item(); + float c1 = cost[i - 1][j].item(); + float c2 = cost[i][j - 1].item(); + + float c = 0; + float t = 0; + + if (c0 < c1 && c0 < c2) { + c = c0; + t = 0; + } else if (c1 < c0 && c1 < c2) { + c = c1; + t = 1; + } else { + c = c2; + t = 2; + } + + cost[i][j] = x[i - 1][j - 1].item() + c; + trace[i][j] = t; + } + } + + return Backtrace(trace); + } + + // namespace is onnxruntime + static auto registry = torch::RegisterOperators("onnxruntime::DynamicTimeWarping", &DynamicTimeWarping); + """) + + torch.utils.cpp_extension.load_inline( + name="DynamicTimeWarping", + cpp_sources=dtw_op_source, + is_python_module=False, + verbose=True, + ) + + # Create symbolic mapping from torch ops to ORT contrib ops + pytorch_export_contrib_ops.register() + + def export_onnx( + self, + onnx_model_path: str, + provider: str, + verbose: bool = True, + use_external_data_format: bool = False, + use_fp16_inputs: bool = False, + use_int32_inputs: bool = True, + ): + """Export word-level timestamps to ONNX + + Args: + onnx_model_path (str): path to save ONNX model + provider (str): provider to use for verifying parity on ONNX model + verbose (bool, optional): print verbose information. Defaults to True. + use_external_data_format (bool, optional): use external data format or not. Defaults to False. + use_fp16_inputs (bool, optional): use float16 inputs for the audio_features. Defaults to False. + use_int32_inputs (bool, optional): use int32 inputs for the decoder_input_ids. Defaults to True. + """ + # Shape of timestamps's tensors: + # Inputs: + # alignment_heads: (num_alignment_heads, 2) + # sot_sequence_length: (1) + # segment_length: (1) + # cross_qk_*: (batch_size, num_heads, sequence_length, num_frames // 2) + # Outputs: + # jump_times: (batch_size, max_length) + + # Definitions: + # alignment_heads: the attention head indices where the Q*K values are highly correlated with word-level timestamps + # (i.e. the alignment between audio and text tokens) + # This is calculated as follows: + # + # ``` + # import base64 + # import gzip + # import numpy as np + # import torch + # + # # base85-encoded (n_layers, n_heads) boolean arrays indicating the cross-attention heads that are + # # highly correlated to the word-level timing, i.e. the alignment between audio and text tokens. + # _ALIGNMENT_HEADS = { + # "tiny.en": b"ABzY8J1N>@0{>%R00Bk>$p{7v037`oCl~+#00", + # "tiny": b"ABzY8bu8Lr0{>%RKn9Fp%m@SkK7Kt=7ytkO", + # "base.en": b"ABzY8;40c<0{>%RzzG;p*o+Vo09|#PsxSZm00", + # "base": b"ABzY8KQ!870{>%RzyTQH3`Q^yNP!>##QT-?_)10{>%RpeA61k&I|OI3I$65C{;;pbCHh0B{qLQ;+}v00", + # "small": b"ABzY8DmU6=0{>%Rpa?J`kvJ6qF(V^F86#Xh7JUGMK}P%R7%R7}kK1fFL7w6%<-Pf*t^=N)Qr&0RR9", + # "large-v1": b"ABzY8r9j$a0{>%R7#4sLmoOs{s)o3~84-RPdcFk!JR%R7=D0pU<_bnWW*tkYAhobTNnu$jnkEkXqp)j;w1Tzk)UH3X%SZd&fFZ2fC2yj", + # "large-v3": b"ABzY8gWO1E0{>%R7(9S+Kn!D~%ngiGaR?*L!iJG9p-nab0JQ=-{D1-g00", + # "large": b"ABzY8gWO1E0{>%R7(9S+Kn!D~%ngiGaR?*L!iJG9p-nab0JQ=-{D1-g00", + # "large-v3-turbo": b"ABzY8j^C+e0{>%RARaKHP%t(lGR*)0g!tONPyhe`", + # "turbo": b"ABzY8j^C+e0{>%RARaKHP%t(lGR*)0g!tONPyhe`", + # } + # + # model_name = "large-v3-turbo" + # array = np.frombuffer( + # gzip.decompress(base64.b85decode(_ALIGNMENT_HEADS[model_name])), dtype=bool + # ).copy() + # mask = torch.from_numpy(array).reshape( + # self.dims.n_text_layer, self.dims.n_text_head + # ) + # self.alignment_heads = mask.to_sparse().indices().T + # ``` + # + # sot_sequence_length: the length of the start-of-transcription sequence before the first token is generated + # Typically the start-of-transcription sequence is [<|startoftranscription|>, <|language_token|>, <|task_token|>] + # so its length is 3. + # + # segment_length: the length (in frames) of the audio segment that is being transcribed + # + # cross_qk_*: the Q*K values for the cross-attention blocks in the decoder + # Every decoder layer has a self-attention block and a cross-attention block so there are `n` cross-attention blocks + # where `n` is the number of decoder layers. + # + # jump_times: the timings where jumps occur in speech + # This allows us to detect when a word began to be spoken by the speaker (start_times) and when a word was finished + # being spoken by the speaker (end_times). + + inputs = self.inputs(use_fp16_inputs=use_fp16_inputs, use_int32_inputs=use_int32_inputs) + input_names = self.input_names() + output_names = self.output_names() + dynamic_axes = get_model_dynamic_axes(self.config, input_names, output_names) + + Path(onnx_model_path).parent.mkdir(parents=True, exist_ok=True) + with tempfile.TemporaryDirectory() as tmp_dir_name: + temp_onnx_model_path = os.path.join(tmp_dir_name, "encoder.onnx") + Path(temp_onnx_model_path).parent.mkdir(parents=True, exist_ok=True) + out_path = temp_onnx_model_path if use_external_data_format else onnx_model_path + + # Create torch ops and map them to ORT contrib ops before export + self.create_torch_ops() + torch.onnx.export( + self, + args=inputs, + f=out_path, + export_params=True, + input_names=input_names, + output_names=output_names, + dynamic_axes=dynamic_axes, + opset_version=17, + do_constant_folding=True, + verbose=verbose, + custom_opsets={"com.microsoft": 1}, + ) + + if use_external_data_format: + model = onnx.load_model(out_path, load_external_data=use_external_data_format) + OnnxModel.save( + model, + onnx_model_path, + save_as_external_data=True, + all_tensors_to_one_file=True, + ) + + self.verify_onnx(onnx_model_path, provider, use_fp16_inputs, use_int32_inputs) + + def verify_onnx( + self, + onnx_model_path: str, + provider: str, + use_fp16_inputs: bool, + use_int32_inputs: bool, + ): + """Verify ONNX model outputs and PyTorch model outputs match + + Args: + onnx_model_path (str): path to save ONNX model + provider (str): execution provider for ONNX model + use_fp16_inputs (bool, optional): use float16 inputs for the cross_qk_{i} + use_int32_inputs (bool, optional): use int32 inputs for the alignment_heads and sot_sequence_length + """ + # Shape of jump times's tensors: + # Inputs: + # alignment_heads: (num_alignment_heads, 2) + # sot_sequence_length: (1) + # segment_length: (1) + # cross_qk_*: (batch_size, num_heads, sequence_length, num_frames // 2) + # Outputs: + # jump_times: (batch_size, max_length) + inputs = self.inputs(use_fp16_inputs=use_fp16_inputs, use_int32_inputs=use_int32_inputs, return_dict=True) + + # Run PyTorch model + pt_outputs = ( + self.forward( + inputs["alignment_heads"], inputs["sot_sequence_length"], inputs["segment_length"], inputs["QKs"] + ) + .detach() + .cpu() + .numpy() + ) + + # Run ONNX model + sess = InferenceSession(onnx_model_path, providers=[provider]) + ort_outputs = sess.run(None, convert_inputs_for_ort(inputs, sess)) + + # Calculate output difference + diff = np.abs(pt_outputs - ort_outputs) + print("Comparing batched jump_times...", flush=True) + print(f"Max diff: {np.max(diff)}", flush=True) diff --git a/onnxruntime/python/tools/transformers/models/whisper/whisper_openai_helper.py b/onnxruntime/python/tools/transformers/models/whisper/whisper_openai_helper.py deleted file mode 100644 index 8c78fb86a211e..0000000000000 --- a/onnxruntime/python/tools/transformers/models/whisper/whisper_openai_helper.py +++ /dev/null @@ -1,84 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- - -import logging - -import torch - -logger = logging.getLogger(__name__) - - -class WhisperDecoderInitOpenai(torch.nn.Module): - """WhisperDecoderInit for Openai.""" - - def __init__( - self, - model: torch.nn.Module, - decoder: torch.nn.Module, - ): - super().__init__() - self.whisper_model = model - self.whisper_decoder = decoder - self.kv_cache = {} - - @torch.no_grad() - def forward( - self, - tokens, - audio_features, - past=None, - remove_hooks=False, - ): - # Create a kv_cache for past_values - past_kv_cache = {} - if past is not None: - # Convert past values from 4D to 3D - past = [torch.transpose(val, 1, 2) for val in past] - past = [val.reshape(val.shape[:2] + (-1,)) for val in past] - half_idx = len(past) // 2 - for idx, block in enumerate(self.whisper_decoder.blocks): - past_kv_cache[block.attn.key] = past[2 * idx] - past_kv_cache[block.attn.value] = past[2 * idx + 1] - past_kv_cache[block.cross_attn.key] = past[2 * idx + half_idx] - past_kv_cache[block.cross_attn.value] = past[2 * idx + half_idx + 1] - - hooks = None - if not self.kv_cache: - self.kv_cache, hooks = self.whisper_model.install_kv_cache_hooks() - - logits = self.whisper_decoder(tokens, audio_features, kv_cache=past_kv_cache) - - # Add concat node for past values - if past is not None: - for block in self.whisper_decoder.blocks: - self.kv_cache[block.attn.key] = torch.cat( - [past_kv_cache[block.attn.key], self.kv_cache[block.attn.key]], dim=1 - ).detach() - self.kv_cache[block.attn.value] = torch.cat( - [past_kv_cache[block.attn.value], self.kv_cache[block.attn.value]], dim=1 - ).detach() - - present_self, present_cross = [], [] - # Group self and cross values - for block in self.whisper_decoder.blocks: - present_self.append(self.kv_cache[block.attn.key]) - present_self.append(self.kv_cache[block.attn.value]) - if past is None: - present_cross.append(self.kv_cache[block.cross_attn.key]) - present_cross.append(self.kv_cache[block.cross_attn.value]) - - present_self = present_self + present_cross - # Add reshape and transpose ops to convert from 3D to 4D - present_self = [ - present_val.reshape(present_val.shape[:2] + (-1, 64)).transpose(1, 2) for present_val in present_self - ] - - # Remove forward hooks to avoid model cloning step - if hooks is not None and remove_hooks: - self.kv_cache = {} - for hook in hooks: - hook.remove() - return logits, present_self diff --git a/onnxruntime/python/tools/transformers/onnx_model.py b/onnxruntime/python/tools/transformers/onnx_model.py index c0310b3e8c663..8add38b5a7d07 100644 --- a/onnxruntime/python/tools/transformers/onnx_model.py +++ b/onnxruntime/python/tools/transformers/onnx_model.py @@ -1183,11 +1183,21 @@ def graph_topological_sort(graph, is_deterministic=False): graph.ClearField("node") graph.node.extend(sorted_nodes) - def topological_sort(self, is_deterministic=False): + def topological_sort(self, is_deterministic=False, dump_model_on_failure=False): # TODO: support graph_topological_sort() in subgraphs # for graph in self.graphs(): # self.graph_topological_sort(graph) - OnnxModel.graph_topological_sort(self.model.graph, is_deterministic) + try: + OnnxModel.graph_topological_sort(self.model.graph, is_deterministic) + except RuntimeError as e: + if dump_model_on_failure: + logger.info( + "Failed to sort graph in topological order. Dumping model to _topo_sort_failed.onnx for debugging." + ) + OnnxModel.save( + self.model, "_topo_sort_failed.onnx", save_as_external_data=True, all_tensors_to_one_file=True + ) + raise e @staticmethod def save( diff --git a/onnxruntime/python/tools/transformers/onnx_model_t5.py b/onnxruntime/python/tools/transformers/onnx_model_t5.py index 33dcc7795a465..de299a970ffd3 100644 --- a/onnxruntime/python/tools/transformers/onnx_model_t5.py +++ b/onnxruntime/python/tools/transformers/onnx_model_t5.py @@ -34,13 +34,13 @@ def __init__( num_heads, attention_mask, use_multi_head_attention=False, - search_op_types=["SkipSimplifiedLayerNormalization", "Add"], + search_op_types=["Softmax"], ) self.static_kv = 1 - def create_attention_node( + def make_attention_node( self, - mask_index: str, + mask_index: str | None, q_matmul: NodeProto, k_matmul: NodeProto, v_matmul: NodeProto, @@ -48,8 +48,8 @@ def create_attention_node( hidden_size: int, input: str, output: str, - add_qk_str: str, - scale: float | None = None, + attn_bias: str | None, + scale: float, ) -> NodeProto | None: """Create an Attention node. Args: @@ -122,14 +122,17 @@ def create_attention_node( attention_node_name + "_qkv_weight", "", ] - if mask_index is not None: + if mask_index: attention_inputs.append(mask_index) else: attention_inputs.append("") - if add_qk_str is not None: + if attn_bias: attention_inputs.append("") # no past - attention_inputs.append(add_qk_str) + attention_inputs.append(attn_bias) + + while attention_inputs and attention_inputs[-1] == "": + attention_inputs.pop() attention_node = helper.make_node( "Attention", @@ -153,50 +156,55 @@ def create_mha_node( query: str, key: str, value: str, - mask_index: str, - res_pos_bias: str, - past_key: str, - past_value: str, + mask_index: str | None, + attn_bias: str | None, + past_key: str | None, + past_value: str | None, output: str, - present_key: str, - present_value: str, + present_key: str | None, + present_value: str | None, num_heads: int, hidden_size: int, ) -> NodeProto | None: - assert num_heads > 0 + assert num_heads > 0 and hidden_size > 0 and query and key and value - if hidden_size > 0 and (hidden_size % num_heads) != 0: + if (hidden_size % num_heads) != 0: logger.debug(f"input hidden size {hidden_size} is not a multiple of num of heads {num_heads}") return None attention_node_name = self.model.create_node_name("MultiHeadAttention") attention_inputs = [ query, - "" if key is None else key, # key - "" if value is None else value, # value + key, + value, "", # bias ] - if mask_index is not None: + + if mask_index: attention_inputs.append(mask_index) else: attention_inputs.append("") - if res_pos_bias is not None: - attention_inputs.append(res_pos_bias) + if attn_bias: + attention_inputs.append(attn_bias) else: attention_inputs.append("") - if past_key is not None: - assert past_value is not None + if past_key: + assert past_value attention_inputs.append(past_key) attention_inputs.append(past_value) + while attention_inputs and attention_inputs[-1] == "": + attention_inputs.pop() + attention_outputs = [output] - if present_key is not None: - assert present_value is not None + if present_key: + assert present_value attention_outputs.append(present_key) attention_outputs.append(present_value) + print(f"{attention_inputs=}, {attention_outputs=}, {attention_node_name=}") attention_node = helper.make_node( "MultiHeadAttention", inputs=attention_inputs, @@ -213,21 +221,23 @@ def create_mha_node( self.increase_counter("MultiHeadAttention") return attention_node - def fuse(self, normalize_node, input_name_to_nodes, output_name_to_node): - self.fuse_t5_encoder(normalize_node, input_name_to_nodes, output_name_to_node) - self.fuse_t5_decoder(normalize_node, input_name_to_nodes, output_name_to_node) - - def fuse_t5_encoder(self, normalize_node, input_name_to_nodes, output_name_to_node): - if normalize_node.op_type != "SkipSimplifiedLayerNormalization" and normalize_node.op_type != "Add": + def fuse(self, node, input_name_to_nodes, output_name_to_node): + if self.fuse_t5_encoder(node, input_name_to_nodes, output_name_to_node): return - qkv_nodes = self.model.match_parent_path( - normalize_node, ["MatMul", "Reshape", "Transpose", "MatMul"], [1, 0, 0, 0], output_name_to_node + self.fuse_t5_decoder(node, input_name_to_nodes, output_name_to_node) + + def fuse_t5_encoder(self, softmax_node, input_name_to_nodes, output_name_to_node): + assert softmax_node.op_type == "Softmax" + qkv_nodes = self.model.match_child_path( + softmax_node, + ["MatMul", "Transpose", "Reshape"], + edges=[(0, 0), (0, 0), (0, 0)], + input_name_to_nodes=input_name_to_nodes, ) if qkv_nodes is None: - return - - _, reshape_qkv, transpose_qkv, matmul_qkv = qkv_nodes + return False + matmul_qkv, _, reshape_qkv = qkv_nodes qkv_shape_nodes = self.model.match_parent_path( reshape_qkv, @@ -236,7 +246,7 @@ def fuse_t5_encoder(self, normalize_node, input_name_to_nodes, output_name_to_no output_name_to_node, ) if qkv_shape_nodes is None: - return + return False input_shape_node = qkv_shape_nodes[-1] v_nodes = self.model.match_parent_path( @@ -246,7 +256,7 @@ def fuse_t5_encoder(self, normalize_node, input_name_to_nodes, output_name_to_no output_name_to_node, ) if v_nodes is None: - return + return False _, reshape_v, matmul_v = v_nodes # todo: check reshape_v parent nodes @@ -257,7 +267,7 @@ def fuse_t5_encoder(self, normalize_node, input_name_to_nodes, output_name_to_no output_name_to_node, ) if qk_nodes is None: - return + return False _, add_qk, matmul_qk = qk_nodes mask_nodes = self.model.match_parent_path( @@ -268,7 +278,9 @@ def fuse_t5_encoder(self, normalize_node, input_name_to_nodes, output_name_to_no ) is_pattern_for_one_graph_input = mask_nodes is None - if mask_nodes is None: + if mask_nodes is not None: + mul_node = mask_nodes[1] + else: # Pattern for SD3 and Flux. mask_nodes = self.model.match_parent_path( add_qk, @@ -276,15 +288,22 @@ def fuse_t5_encoder(self, normalize_node, input_name_to_nodes, output_name_to_no [1, 1, 0, 0, 1, 0], output_name_to_node, ) + + # If the model is not optimized by ORT, there might be an additional Cast node. if mask_nodes is None: - return + mask_nodes = self.model.match_parent_path( + add_qk, + ["Add", "Slice", "Mul", "Sub", "Cast", "Unsqueeze", "Unsqueeze"], + [1, 1, 0, 0, 1, 0, 0], + output_name_to_node, + ) + if mask_nodes is None: + return False mul_node = mask_nodes[2] - else: - mul_node = mask_nodes[1] _, mul_val = self.model.get_constant_input(mul_node) if mul_val is None: - return + return False if mul_val != -10000: self.mask_filter_value = float(mul_val) @@ -327,7 +346,7 @@ def fuse_t5_encoder(self, normalize_node, input_name_to_nodes, output_name_to_no [1, 0, 0], ) if rpb_nodes is None: - return + return False res_pos_bias = rpb_nodes[-1].output[0] @@ -337,8 +356,8 @@ def fuse_t5_encoder(self, normalize_node, input_name_to_nodes, output_name_to_no [1, 0, 0], ) if k_nodes is None: - return - _, reshape_k, matmul_k = k_nodes + return False + _, _, matmul_k = k_nodes # todo: check reshape_k parent nodes q_nodes = self.model.match_parent_path( @@ -347,50 +366,50 @@ def fuse_t5_encoder(self, normalize_node, input_name_to_nodes, output_name_to_no [0, 0, 0], ) if q_nodes is None: - return + return False - transpose_q, reshape_q, matmul_q = q_nodes + _, reshape_q, matmul_q = q_nodes # todo: check reshape_q parent nodes if matmul_q.input[0] != input_shape_node.input[0]: - return + return False q_num_heads, q_hidden_size = self.get_num_heads_and_hidden_size(reshape_q) - new_node = self.create_attention_node( + new_node = self.make_attention_node( mask_index, matmul_q, matmul_k, matmul_v, - q_num_heads, - q_hidden_size, - input_shape_node.input[0], - reshape_qkv.output[0], - res_pos_bias, - 1.0, + num_heads=q_num_heads, + hidden_size=q_hidden_size, + input=input_shape_node.input[0], + output=reshape_qkv.output[0], + attn_bias=res_pos_bias, + scale=1.0, ) if new_node is None: - return + return False self.nodes_to_add.append(new_node) self.node_name_to_graph_name[new_node.name] = self.this_graph_name self.nodes_to_remove.append(reshape_qkv) self.prune_graph = True + return True - def fuse_t5_decoder(self, normalize_node, input_name_to_nodes, output_name_to_node): - if normalize_node.op_type != "SkipSimplifiedLayerNormalization" and normalize_node.op_type != "Add": - return + def fuse_t5_decoder(self, softmax_node, input_name_to_nodes, output_name_to_node): + assert softmax_node.op_type == "Softmax" - qkv_nodes = self.model.match_parent_path( - normalize_node, - ["MatMul", "Reshape", "Transpose", "MatMul"], - [1, 0, 0, 0], + qkv_nodes = self.model.match_child_path( + softmax_node, + ["MatMul", "Transpose", "Reshape"], + edges=[(0, 0), (0, 0), (0, 0)], + input_name_to_nodes=input_name_to_nodes, ) if qkv_nodes is None: return - - _, reshape_qkv, transpose_qkv, matmul_qkv = qkv_nodes + matmul_qkv, _transpose_qkv, reshape_qkv = qkv_nodes qkv_shape_nodes = self.model.match_parent_path( reshape_qkv, @@ -462,11 +481,17 @@ def fuse_t5_decoder(self, normalize_node, input_name_to_nodes, output_name_to_no ["Add", "Mul", "Sub", "Cast", "Unsqueeze", "Unsqueeze"], [1, 1, 0, 1, 0, 0], ) - if mask_nodes is None: - return - mul_node = mask_nodes[1] - if mask_nodes[1].op_type != "Mul": - return + if mask_nodes is not None: + mul_node = mask_nodes[1] + else: + mask_nodes = self.model.match_parent_path( + add_qk, + ["Add", "Slice", "Mul", "Sub", "Cast", "Unsqueeze", "Unsqueeze"], + [1, 1, 0, 0, 1, 0, 0], + ) + if mask_nodes is None: + return + mul_node = mask_nodes[2] _, mul_val = self.model.get_constant_input(mul_node) if mul_val != -10000: @@ -474,22 +499,19 @@ def fuse_t5_decoder(self, normalize_node, input_name_to_nodes, output_name_to_no mask_index = self.attention_mask.process_mask(mask_nodes[-1].input[0]) else: - rpb_nodes = self.model.match_parent_path( + matched_path_index, _, _ = self.model.match_parent_paths( add_qk, - ["Add", "Slice"], - [1, 0], + [ + (["Add", "Slice"], [1, 0]), + (["Add", "RelativePositionBias"], [1, 0]), + ], + output_name_to_node, ) - if rpb_nodes is not None: - res_pos_bias = add_qk.input[1] - else: - rpb_nodes = self.model.match_parent_path( - add_qk, - ["Add", "RelativePositionBias"], - [1, 0], - ) - if rpb_nodes is None: - return - res_pos_bias = add_qk.input[1] + if matched_path_index < 0: + logger.debug("Skip MultiHeadAttention fusion since attention bias pattern not matched") + return + + res_pos_bias = add_qk.input[1] key = None past_key = None @@ -608,56 +630,73 @@ def fuse_t5_decoder(self, normalize_node, input_name_to_nodes, output_name_to_no past_key = None past_value = None + if not (key and value and q_num_heads > 0 and q_hidden_size > 0): + return + new_node = self.create_mha_node( - matmul_q.output[0], - key, - value, - mask_index, - res_pos_bias, - past_key, - past_value, - reshape_qkv.output[0], - present_key, - present_value, - q_num_heads, - q_hidden_size, + query=matmul_q.output[0], + key=key, + value=value, + mask_index=mask_index, + attn_bias=res_pos_bias, + past_key=past_key, + past_value=past_value, + output=reshape_qkv.output[0], + present_key=present_key, + present_value=present_value, + num_heads=q_num_heads, + hidden_size=q_hidden_size, ) - if new_node is None: - return - self.nodes_to_add.append(new_node) - self.node_name_to_graph_name[new_node.name] = self.this_graph_name + if new_node: + self.nodes_to_add.append(new_node) + self.node_name_to_graph_name[new_node.name] = self.this_graph_name - self.nodes_to_remove.append(reshape_qkv) + # Since present_* is graph output, we need update the graph to avoid circular. + if present_key or present_value: + for graph_output in [present_key, present_value]: + if not (graph_output and self.model.find_graph_output(graph_output)): + print(f"{graph_output=} does not exist in graph output") + return + assert graph_output in output_name_to_node + output_name_to_node[graph_output].output[0] = graph_output + "_copy" + self.model.replace_input_of_all_nodes(graph_output, graph_output + "_copy") - self.prune_graph = True + self.nodes_to_remove.append(reshape_qkv) + self.prune_graph = False class FusionRelativePositionBiasBlock(Fusion): - def __init__(self, model: OnnxModel, max_distance: int): - super().__init__(model, "RelativePositionBias", ["Add", "Slice"]) - self.max_distance = max_distance - self.is_bidirectional = False + def __init__(self, model: OnnxModel): + super().__init__(model, "RelativePositionBias", ["Softmax"]) def fuse(self, node, input_name_to_nodes, output_name_to_node): - # TODO: Optimization opportunity: only last dimension of relative_position_bias is used in decoder. - # Cuda kernel can be optimized to only compute last dimension. - if node.op_type != "Add" and node.op_type != "Slice": - return - compute_bias_nodes = self.model.match_parent_path( - node, ["Unsqueeze", "Transpose", "Gather", "Where"], [0, 0, 0, 1], output_name_to_node + node, + ["Add", "Add", "Slice", "Unsqueeze", "Transpose", "Gather", "Where"], + [0, 1, 0, 0, 0, 0, 1], + output_name_to_node, ) + if compute_bias_nodes is None: compute_bias_nodes = self.model.match_parent_path( - node, ["Unsqueeze", "Transpose", "Gather", "Add", "Where"], [0, 0, 0, 1, 1], output_name_to_node + node, + ["Add", "Add", "Slice", "Unsqueeze", "Transpose", "Gather", "Add", "Where"], + [0, 1, 0, 0, 0, 0, 1, 1], + output_name_to_node, ) if compute_bias_nodes is None: return - gather = compute_bias_nodes[2] + gather = compute_bias_nodes[5] where = compute_bias_nodes[-1] - unsqueeze = compute_bias_nodes[0] + slice = compute_bias_nodes[2] + unsqueeze = compute_bias_nodes[3] + + # Current fusion will not remove the node until the graph is processed. + # This avoids to fuse it again when it is shared by multiple layers. + if unsqueeze in self.nodes_to_remove: + return compute_buckets_nodes = self.model.match_parent_path( where, @@ -668,12 +707,8 @@ def fuse(self, node, input_name_to_nodes, output_name_to_node): if compute_buckets_nodes is None: return - # It is possible to deduce max_distance from a Div node: - # The value of self.model.get_constant_value(compute_buckets_nodes[-3].input[1]) is close to - # math.log(max_distance / (relative_attention_num_buckets // (4 if is_bidirectional else 2))) - # See https://github.com/huggingface/transformers/blob/608e163b527eaee41e650ffb9eb4c422d2679902/src/transformers/models/t5/modeling_t5.py#L397. - # Most t5 models use max_distance=128, so we hardcode it unitl we see a model with different value. - # TODO: maybe add a sanity check here. + # This value is to used to compute max_distance later. + log_max = self.model.get_constant_value(compute_buckets_nodes[-3].input[1]) div = compute_buckets_nodes[-1] @@ -683,21 +718,33 @@ def fuse(self, node, input_name_to_nodes, output_name_to_node): [0, 0, 0, 1, 0, 0, 0, 0], output_name_to_node, ) + + is_bidirectional = False if range_nodes is None: range_nodes = self.model.match_parent_path( div, ["Cast", "Abs", "Sub", "Unsqueeze", "Range"], [0, 0, 0, 0, 0], output_name_to_node ) - self.is_bidirectional = True + is_bidirectional = True if range_nodes is None: return - range_node = range_nodes[-1] - self.nodes_to_remove.append(unsqueeze) - self.prune_graph = True + # Double check that the constant relative to max_distance and relative_attention_num_buckets. + # Most t5 models use max_distance=128, so we hardcode it unitl we see a model with different value. + + # The log_max is the value of the following formula: + # math.log(max_distance / (relative_attention_num_buckets // (4 if is_bidirectional else 2))) + # See https://github.com/huggingface/transformers/blob/608e163b527eaee41e650ffb9eb4c422d2679902/src/transformers/models/t5/modeling_t5.py#L397. + # Here is the value based on max_distance=128 and relative_attention_num_buckets=32: + max_distance = int(np.round(np.exp(log_max) * (32 // (4 if is_bidirectional else 2)))) + if max_distance != 128: + logger.warning( + f"max_distance is {max_distance}, which is different from the default value 128. " + "Please double check the model configuration." + ) node_name = self.model.create_node_name( - "RelativePositionBias", name_prefix="RelPosBias_" + ("encoder" if self.is_bidirectional else "decoder") + "RelativePositionBias", name_prefix="RelPosBias_" + ("encoder" if is_bidirectional else "decoder") ) table_weight_i = self.model.get_initializer(gather.input[0]) @@ -712,22 +759,64 @@ def fuse(self, node, input_name_to_nodes, output_name_to_node): vals=table_weight_t.tobytes(), raw=True, ) - self.model.add_initializer(bias_table, self.this_graph_name) + + # Relative position is like the following in encoder: + # seq_len + # | + # Range(0, *) + # / \ + # Unsqueeze(axes=0) Unsqueeze(axes=1) + # \ / + # Sub + # | + # Abs + # + # Relative position is like the following in decoder: + # past_seq_len seq_len + # \ / + # Add + # / \ + # Range(0, *) Range(0, *) + # \ / + # Sub + # Note that the graph will slice the attention bias to get last seq_len rows. + # + # In new version of transformers, the pattern of decoder is changed like the following + # + # total_seq_len Range(start=past_seq_len, end=total_seq_len) + # | | + # Range(0, *) Unsqueeze(axes=1) + # | | + # Unsqueeze(axes=0) Cast(to=int64) + # \ / + # Sub + # Currently, there is still Slice to get last seq_len rows so end result is same. + # But need to be careful that the shape of bias tensor is changed before Slice. + # + # RelativePositionBias operator requires query_length == key_length so we shall pass in total_seq_len. + # Here we get the end value of the Range node as length to pass to the RelativePositionBias node. + + # TODO: Optimization opportunity: change RelativePositionBias op to support query_length != key_length. + # only compute seq_len rows, then we can remove the Slice after the RelativePositionBias node. inputs = [bias_table.name, range_node.input[1], range_node.input[1]] - outputs = [unsqueeze.output[0]] + + # Use a new tensor name since the shape might be different as mentioned above. + bias_output = node_name + "_rel_pos_bias" + slice.input[0] = bias_output + rpb_node = helper.make_node( "RelativePositionBias", inputs=inputs, - outputs=outputs, + outputs=[bias_output], name=node_name, ) rpb_node.domain = "com.microsoft" - rpb_node.attribute.extend([helper.make_attribute("max_distance", self.max_distance)]) - rpb_node.attribute.extend([helper.make_attribute("is_bidirectional", self.is_bidirectional)]) - - self.nodes_to_add.append(rpb_node) + rpb_node.attribute.extend([helper.make_attribute("max_distance", max_distance)]) + rpb_node.attribute.extend([helper.make_attribute("is_bidirectional", is_bidirectional)]) self.node_name_to_graph_name[rpb_node.name] = self.this_graph_name + self.nodes_to_add.append(rpb_node) + self.prune_graph = True class T5OnnxModel(BertOnnxModel): @@ -744,7 +833,7 @@ def __init__(self, model, num_heads: int = 0, hidden_size: int = 0): self.attention_fusion = FusionT5Attention(self, self.hidden_size, self.num_heads, self.attention_mask) self.layer_norm_fusion = FusionSimplifiedLayerNormalization(self) self.skip_layer_norm_fusion = FusionSkipSimplifiedLayerNormalization(self) - self.rpb_fusion = FusionRelativePositionBiasBlock(self, 128) + self.rpb_fusion = FusionRelativePositionBiasBlock(self) def fuse_attention(self): self.attention_fusion.apply() diff --git a/onnxruntime/python/tools/transformers/models/t5/past_helper.py b/onnxruntime/python/tools/transformers/past_helper.py similarity index 100% rename from onnxruntime/python/tools/transformers/models/t5/past_helper.py rename to onnxruntime/python/tools/transformers/past_helper.py diff --git a/onnxruntime/test/contrib_ops/attention_op_test_helper.cc b/onnxruntime/test/contrib_ops/attention_op_test_helper.cc index 5df521bd6381d..fc65963474cdb 100644 --- a/onnxruntime/test/contrib_ops/attention_op_test_helper.cc +++ b/onnxruntime/test/contrib_ops/attention_op_test_helper.cc @@ -520,6 +520,75 @@ void GetCrossAttentionData_WithPastPassedInDirectly_NoMask(AttentionTestData& da data.fp16_output_data = data.fp32_output_data; } +void GetSelfAttention_PastPresentBufferShare_UsingDMMHAInsideMHA(AttentionTestData& data) { + int num_heads = 2; + int head_size = 32; + data.hidden_size = num_heads * head_size; + data.v_hidden_size = num_heads * head_size; + data.num_heads = num_heads; + data.batch_size = 2; + data.sequence_length = 1; + data.kv_sequence_length = 1; + data.mask_type = AttentionMaskType::MASK_2D_KEY_PADDING; + + data.past_seq_len_data = {4}; + data.cache_indir_data = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + data.num_beams = 1; + data.max_sequence_length = 6; + + data.skip_kernel_types = { + AttentionKernelType::AttentionKernel_TrtFlashAttention, + AttentionKernelType::AttentionKernel_TrtFusedCrossAttention, + AttentionKernelType::AttentionKernel_TrtFusedAttention, + AttentionKernelType::AttentionKernel_CutlassMemoryEfficientAttention, + }; + + LoadTensor("SelfAttention_PastPresentBufferShare_UsingDMMHAInsideMHA.query_data", data.query_data); + LoadTensor("SelfAttention_PastPresentBufferShare_UsingDMMHAInsideMHA.key_data", data.key_data); + LoadTensor("SelfAttention_PastPresentBufferShare_UsingDMMHAInsideMHA.value_data", data.value_data); + LoadTensor("SelfAttention_PastPresentBufferShare_UsingDMMHAInsideMHA.bias_data", data.bias_data); + LoadTensor("SelfAttention_PastPresentBufferShare_UsingDMMHAInsideMHA.past_key_data", data.past_key_data); + LoadTensor("SelfAttention_PastPresentBufferShare_UsingDMMHAInsideMHA.past_value_data", data.past_value_data); + LoadTensor("SelfAttention_PastPresentBufferShare_UsingDMMHAInsideMHA.fp32_output_data", data.fp32_output_data); + LoadTensor("SelfAttention_PastPresentBufferShare_UsingDMMHAInsideMHA.present_key_data", data.present_key_data); + LoadTensor("SelfAttention_PastPresentBufferShare_UsingDMMHAInsideMHA.present_value_data", data.present_value_data); + data.is_static_kv = false; + data.buffer_share = true; +} + +void GetCrossAttention_DiffSequenceLengths_UsingDMMHAInsideMHA(AttentionTestData& data) { + int num_heads = 2; + int head_size = 32; + data.hidden_size = num_heads * head_size; + data.v_hidden_size = num_heads * head_size; + data.num_heads = num_heads; + data.batch_size = 2; + data.sequence_length = 1; + data.kv_sequence_length = 10; + data.mask_type = AttentionMaskType::MASK_NONE; + + data.past_seq_len_data = {4}; + data.cache_indir_data = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + data.num_beams = 1; + data.max_sequence_length = 6; + + data.skip_kernel_types = { + AttentionKernelType::AttentionKernel_TrtFlashAttention, + AttentionKernelType::AttentionKernel_TrtFusedCrossAttention, + AttentionKernelType::AttentionKernel_TrtFusedAttention, + AttentionKernelType::AttentionKernel_CutlassMemoryEfficientAttention, + }; + + LoadTensor("CrossAttention_DiffSequenceLengths_UsingDMMHAInsideMHA.query_data", data.query_data); + LoadTensor("CrossAttention_DiffSequenceLengths_UsingDMMHAInsideMHA.past_key_data", data.past_key_data); + LoadTensor("CrossAttention_DiffSequenceLengths_UsingDMMHAInsideMHA.past_value_data", data.past_value_data); + LoadTensor("CrossAttention_DiffSequenceLengths_UsingDMMHAInsideMHA.bias_data", data.bias_data); + LoadTensor("CrossAttention_DiffSequenceLengths_UsingDMMHAInsideMHA.fp32_output_data", data.fp32_output_data); + LoadTensor("CrossAttention_DiffSequenceLengths_UsingDMMHAInsideMHA.fp32_output_qk_data", data.fp32_output_qk_data); + data.is_static_kv = true; + data.buffer_share = false; +} + void GetCausal_EmptyPastState(std::vector& input, std::vector& output, std::vector& present) { LoadTensor("Causal_EmptyPastState.input_data", input); LoadTensor("Causal_EmptyPastState.output_data", output); diff --git a/onnxruntime/test/contrib_ops/attention_op_test_helper.h b/onnxruntime/test/contrib_ops/attention_op_test_helper.h index b0dbe6e7b4ac7..73e39042e7f0b 100644 --- a/onnxruntime/test/contrib_ops/attention_op_test_helper.h +++ b/onnxruntime/test/contrib_ops/attention_op_test_helper.h @@ -12,6 +12,7 @@ namespace test { struct BaseAttentionTestData { bool is_static_kv = true; + bool buffer_share = false; int hidden_size; int v_hidden_size; int num_heads; @@ -33,12 +34,20 @@ struct BaseAttentionTestData { std::vector past_key_data; std::vector past_value_data; + std::vector past_seq_len_data; + std::vector cache_indir_data; + int num_beams; + int max_sequence_length; + std::vector fp32_output_data; std::vector fp16_output_data; std::vector present_key_data; std::vector present_value_data; + std::vector fp32_output_qk_data; + std::vector fp16_output_qk_data; + std::vector skip_kernel_types; // skip some kernels if they do not supported this test case. }; @@ -86,6 +95,9 @@ void GetSelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoAttnBias(Attenti void GetSelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoAttnBias_NoBias(AttentionTestData& data); void GetCrossAttentionData_WithPastPassedInDirectly_NoMask(AttentionTestData& data); +void GetSelfAttention_PastPresentBufferShare_UsingDMMHAInsideMHA(AttentionTestData& data); +void GetCrossAttention_DiffSequenceLengths_UsingDMMHAInsideMHA(AttentionTestData& data); + void GetCausal_EmptyPastState(std::vector& input, std::vector& output, std::vector& present); void GetAttentionDataCutlassAttnBias(AttentionTestData& data); diff --git a/onnxruntime/test/contrib_ops/beam_search_test.cc b/onnxruntime/test/contrib_ops/beam_search_test.cc index df670012f54c0..367553a28f166 100644 --- a/onnxruntime/test/contrib_ops/beam_search_test.cc +++ b/onnxruntime/test/contrib_ops/beam_search_test.cc @@ -403,9 +403,6 @@ TEST(BeamSearchTest, GptBeamSearchFp16_VocabPadded) { } TEST(BeamSearchTest, DummyT5) { -#if defined(USE_CUDA) && defined(USE_DML) - SKIP_CUDA_TEST_WITH_DML; -#endif // dummy_t5.onnx model generated using following command: // python onnxruntime/test/testdata/dummy_t5_generator.py --output-path dummy_t5.onnx ModelTester tester(CurrentTestName(), ORT_TSTR("testdata/dummy_t5.onnx")); @@ -419,9 +416,6 @@ TEST(BeamSearchTest, DummyT5) { } TEST(BeamSearchTest, DummyT5WithOuterScopeInitializers) { -#if defined(USE_CUDA) && defined(USE_DML) - SKIP_CUDA_TEST_WITH_DML; -#endif // dummy_t5_with_outer_scope_initializers.onnx model generated using following command: // python onnxruntime/test/testdata/dummy_t5_generator.py --output-path dummy_t5_with_outer_scope_initializers.onnx --move-initializers ModelTester tester(CurrentTestName(), ORT_TSTR("testdata/dummy_t5_with_outer_scope_initializers.onnx")); @@ -448,9 +442,6 @@ TEST(BeamSearchTest, DummyT5WithSequenceInputIds) { } TEST(BeamSearchTest, DummyT5PointerGenerator) { -#if defined(USE_CUDA) && defined(USE_DML) - SKIP_CUDA_TEST_WITH_DML; -#endif // dummy_t5_pointer_generator.onnx model generated using following command: // python onnxruntime/test/testdata/dummy_t5_generator.py --output-path dummy_t5_pointer_generator.onnx --decoder-needs-input-ids ModelTester tester(CurrentTestName(), ORT_TSTR("testdata/dummy_t5_pointer_generator.onnx")); diff --git a/onnxruntime/test/contrib_ops/decoder_masked_multihead_attention_op_test.cc b/onnxruntime/test/contrib_ops/decoder_masked_multihead_attention_op_test.cc index 208545eacf224..7cdbad3ef80a7 100644 --- a/onnxruntime/test/contrib_ops/decoder_masked_multihead_attention_op_test.cc +++ b/onnxruntime/test/contrib_ops/decoder_masked_multihead_attention_op_test.cc @@ -752,7 +752,7 @@ static void TestDecoderMaskedMultiHeadAttention(bool is_cross_attn = true, bool int kv_sequence_length = 16; int head_size = 32; int num_heads = 12; - int beam_width = 4; + int beam_width = 1; int hidden_size = head_size * num_heads; OpTester tester("DecoderMaskedMultiHeadAttention", 1, onnxruntime::kMSDomain); @@ -766,53 +766,54 @@ static void TestDecoderMaskedMultiHeadAttention(bool is_cross_attn = true, bool tester.AddAttribute("output_qk", static_cast(is_cross_attn)); // Inputs and outputs - auto query = CreateRandom(batch_size * 1 * hidden_size); - tester.AddInput("query", {batch_size, 1, hidden_size}, query); + int batch_beam_size = batch_size * beam_width; + auto query = CreateRandom(batch_beam_size * 1 * hidden_size); + tester.AddInput("query", {batch_beam_size, 1, hidden_size}, query); if (is_cross_attn) { - auto key = CreateRandom(batch_size * num_heads * kv_sequence_length * head_size); + auto key = CreateRandom(batch_beam_size * num_heads * kv_sequence_length * head_size); std::vector reordered_key; if (use_cuda) { - reordered_key = ReorderKVCache(key, batch_size, num_heads, + reordered_key = ReorderKVCache(key, batch_beam_size, num_heads, kv_sequence_length, head_size, kv_sequence_length, false); } - auto value = CreateRandom(batch_size * num_heads * kv_sequence_length * head_size); - tester.AddInput("key", {batch_size, num_heads, kv_sequence_length, head_size}, (use_cuda ? reordered_key : key)); - tester.AddInput("value", {batch_size, num_heads, kv_sequence_length, head_size}, - CreateRandom(batch_size * num_heads * kv_sequence_length * head_size)); + auto value = CreateRandom(batch_beam_size * num_heads * kv_sequence_length * head_size); + tester.AddInput("key", {batch_beam_size, num_heads, kv_sequence_length, head_size}, (use_cuda ? reordered_key : key)); + tester.AddInput("value", {batch_beam_size, num_heads, kv_sequence_length, head_size}, + CreateRandom(batch_beam_size * num_heads * kv_sequence_length * head_size)); - const std::vector mask_index_dims = {batch_size, kv_sequence_length}; + const std::vector mask_index_dims = {batch_beam_size, kv_sequence_length}; auto mask_index = generator.Discrete(mask_index_dims, AsSpan({0, 1})); - tester.AddInput("mask_index", {batch_size, kv_sequence_length}, mask_index); + tester.AddInput("mask_index", {batch_beam_size, kv_sequence_length}, mask_index); // Calculate Softmax(Q * K^T + (Optional) mask) * V std::vector empty_attention_bias; - auto output_qk = CalculateOutputQK(query, key, mask_index, empty_attention_bias, batch_size, num_heads, + auto output_qk = CalculateOutputQK(query, key, mask_index, empty_attention_bias, batch_beam_size, num_heads, kv_sequence_length, kv_sequence_length, head_size); std::vector output_qk_float(output_qk.size()); for (size_t i = 0; i < output_qk.size(); ++i) { output_qk_float[i] = static_cast(output_qk[i]); } - auto softmax = Softmax_QK_Transpose(output_qk.data(), batch_size, num_heads, 1, kv_sequence_length); - auto output = CalculateOutput(softmax, value, batch_size, num_heads, + auto softmax = Softmax_QK_Transpose(output_qk.data(), batch_beam_size, num_heads, 1, kv_sequence_length); + auto output = CalculateOutput(softmax, value, batch_beam_size, num_heads, kv_sequence_length, kv_sequence_length, head_size); - tester.AddOutput("output", {batch_size, 1, hidden_size}, output); + tester.AddOutput("output", {batch_beam_size, 1, hidden_size}, output); tester.AddOptionalOutputEdge(); // optional present_key tester.AddOptionalOutputEdge(); // optional present_value - tester.AddOutput("qk", {batch_size, num_heads, 1, kv_sequence_length}, output_qk_float); + tester.AddOutput("qk", {batch_beam_size, num_heads, 1, kv_sequence_length}, output_qk_float); } else { int max_sequence_length = past_sequence_length + 10; int total_sequence_length = past_sequence_length + 1; - auto key = CreateRandom(batch_size * hidden_size); - auto value = CreateRandom(batch_size * hidden_size); - tester.AddInput("key", {batch_size, 1, hidden_size}, key); - tester.AddInput("value", {batch_size, 1, hidden_size}, value); + auto key = CreateRandom(batch_beam_size * hidden_size); + auto value = CreateRandom(batch_beam_size * hidden_size); + tester.AddInput("key", {batch_beam_size, 1, hidden_size}, key); + tester.AddInput("value", {batch_beam_size, 1, hidden_size}, value); - const std::vector mask_index_dims = {batch_size, total_sequence_length}; + const std::vector mask_index_dims = {batch_beam_size, total_sequence_length}; auto mask_index = generator.Discrete(mask_index_dims, AsSpan({0, 1})); - tester.AddInput("mask_index", {batch_size, total_sequence_length}, mask_index); + tester.AddInput("mask_index", {batch_beam_size, total_sequence_length}, mask_index); std::vector attention_bias_dims = {1, 1, 1, total_sequence_length}; auto attention_bias_float = random.Gaussian(attention_bias_dims, 0.0f, 0.3f); std::vector attention_bias(attention_bias_float.size()); @@ -821,28 +822,28 @@ static void TestDecoderMaskedMultiHeadAttention(bool is_cross_attn = true, bool } tester.AddInput("attention_bias", {1, 1, 1, total_sequence_length}, attention_bias); - auto past_key = CreateRandom(batch_size * num_heads * max_sequence_length * head_size); - auto past_value = CreateRandom(batch_size * num_heads * max_sequence_length * head_size); + auto past_key = CreateRandom(batch_beam_size * num_heads * max_sequence_length * head_size); + auto past_value = CreateRandom(batch_beam_size * num_heads * max_sequence_length * head_size); std::vector reordered_past_key; // For CUDA, we need to reorder past key if (use_cuda) { - reordered_past_key = ReorderKVCache(past_key, batch_size, num_heads, + reordered_past_key = ReorderKVCache(past_key, batch_beam_size, num_heads, past_sequence_length, head_size, max_sequence_length, false); } - tester.AddInput("past_key", {batch_size, num_heads, max_sequence_length, head_size}, + tester.AddInput("past_key", {batch_beam_size, num_heads, max_sequence_length, head_size}, (use_cuda ? reordered_past_key : past_key)); - tester.AddInput("past_value", {batch_size, num_heads, max_sequence_length, head_size}, past_value); + tester.AddInput("past_value", {batch_beam_size, num_heads, max_sequence_length, head_size}, past_value); // merge past key and value with current key and value - auto merged_key = MergePast(past_key, key, batch_size, num_heads, + auto merged_key = MergePast(past_key, key, batch_beam_size, num_heads, past_sequence_length, max_sequence_length, head_size); std::vector merged_reordered_key; if (use_cuda) { - merged_reordered_key = MergeReorderedKVCacheWithK(reordered_past_key, key.data(), batch_size, num_heads, + merged_reordered_key = MergeReorderedKVCacheWithK(reordered_past_key, key.data(), batch_beam_size, num_heads, past_sequence_length, max_sequence_length, head_size, false); } - auto merged_value = MergePast(past_value, value, batch_size, num_heads, + auto merged_value = MergePast(past_value, value, batch_beam_size, num_heads, past_sequence_length, max_sequence_length, head_size); tester.AddInput("past_sequence_length", {1}, {past_sequence_length}); @@ -868,15 +869,15 @@ static void TestDecoderMaskedMultiHeadAttention(bool is_cross_attn = true, bool // Calculate Softmax(Q * K^T + (Optional) mask) * V auto output_qk = CalculateOutputQK(query, (beam_width > 1 ? mod_merged_key : merged_key), mask_index, attention_bias, - batch_size, num_heads, total_sequence_length, max_sequence_length, head_size); - auto softmax = Softmax_QK_Transpose(output_qk.data(), batch_size, num_heads, 1, total_sequence_length); + batch_beam_size, num_heads, total_sequence_length, max_sequence_length, head_size); + auto softmax = Softmax_QK_Transpose(output_qk.data(), batch_beam_size, num_heads, 1, total_sequence_length); auto output = CalculateOutput(softmax, (beam_width > 1 ? mod_merged_value : merged_value), - batch_size, num_heads, total_sequence_length, max_sequence_length, head_size); + batch_beam_size, num_heads, total_sequence_length, max_sequence_length, head_size); - tester.AddOutput("output", {batch_size, 1, hidden_size}, output); - tester.AddOutput("present_key", {batch_size, num_heads, max_sequence_length, head_size}, + tester.AddOutput("output", {batch_beam_size, 1, hidden_size}, output); + tester.AddOutput("present_key", {batch_beam_size, num_heads, max_sequence_length, head_size}, (use_cuda ? merged_reordered_key : merged_key)); - tester.AddOutput("present_value", {batch_size, num_heads, max_sequence_length, head_size}, merged_value); + tester.AddOutput("present_value", {batch_beam_size, num_heads, max_sequence_length, head_size}, merged_value); } if (std::is_same::value) { diff --git a/onnxruntime/test/contrib_ops/fused_conv_test.cc b/onnxruntime/test/contrib_ops/fused_conv_test.cc index e6fe0ec0e45a3..0dd69a49972e8 100644 --- a/onnxruntime/test/contrib_ops/fused_conv_test.cc +++ b/onnxruntime/test/contrib_ops/fused_conv_test.cc @@ -33,14 +33,16 @@ void TestConvOp(const ConvOpAndTestAttributes& attributes, bool disable_cpu = false, bool disable_cuda = false, bool disable_rocm = false, + bool disable_webgpu = false, bool use_float16 = false, bool weight_is_initializer = false) { bool enable_cuda = HasCudaEnvironment(0) && !use_float16 && !disable_cuda; // Only ROCm EP supports float16. bool enable_rocm = (nullptr != DefaultRocmExecutionProvider().get()) && !disable_rocm; + bool enable_webgpu = (nullptr != DefaultWebGpuExecutionProvider().get()) && !disable_webgpu; bool enable_cpu = (nullptr != DefaultCpuExecutionProvider().get()) && !use_float16 && !disable_cpu; - if (enable_cuda || enable_rocm || enable_cpu) { + if (enable_cuda || enable_rocm || enable_cpu || enable_webgpu) { OpTester test("FusedConv", 1, onnxruntime::kMSDomain); test.AddAttribute("group", attributes.group); test.AddAttribute("kernel_shape", attributes.kernel_shape); @@ -96,6 +98,10 @@ void TestConvOp(const ConvOpAndTestAttributes& attributes, execution_providers.push_back(DefaultRocmExecutionProvider()); } + if (enable_webgpu) { + execution_providers.push_back(DefaultWebGpuExecutionProvider()); + } + if (enable_cpu) { execution_providers.push_back(DefaultCpuExecutionProvider()); } @@ -110,15 +116,16 @@ void RunConvOp(const ConvOpAndTestAttributes& attributes, const vector& expected_output_shape, bool disable_cpu = false, bool disable_cuda = false, - bool disable_rocm = false) { + bool disable_rocm = false, + bool disable_webgpu = false) { bool weight_is_initializer = false; bool use_float16 = false; TestConvOp(attributes, inputs, input_shapes, expected_output, expected_output_shape, - disable_cpu, disable_cuda, disable_rocm, use_float16, weight_is_initializer); + disable_cpu, disable_cuda, disable_rocm, disable_webgpu, use_float16, weight_is_initializer); use_float16 = true; TestConvOp(attributes, inputs, input_shapes, expected_output, expected_output_shape, - disable_cpu, disable_cuda, disable_rocm, use_float16, weight_is_initializer); + disable_cpu, disable_cuda, disable_rocm, disable_webgpu, use_float16, weight_is_initializer); } TEST(FusedConvTest, Conv2D_HardSigmoid) { @@ -139,7 +146,7 @@ TEST(FusedConvTest, Conv2D_HardSigmoid) { vector W_shape = {2, 1, 2, 2}; vector Y_shape = {1, 2, 2, 2}; auto expected_vals = {0.8f, 0.9f, 1.0f, 1.0f, 0.2f, 0.1f, 0.0f, 0.0f}; - RunConvOp(attrs, {X, W}, {X_shape, W_shape}, expected_vals, Y_shape, false, true, true); + RunConvOp(attrs, {X, W}, {X_shape, W_shape}, expected_vals, Y_shape, false, true, true, true); } TEST(FusedConvTest, Conv2D_Relu) { @@ -233,7 +240,7 @@ TEST(FusedConvTest, Cpu_Conv2D_Bias_Z_Relu) { vector Z = {-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; vector Z_shape = {1, 2, 2, 2}; auto expected_vals = {12.0f, 17.0f, 25.0f, 29.0f, 11.0f, 15.0f, 23.0f, 28.0f}; - RunConvOp(attrs, {X, W, B, Z}, {X_shape, W_shape, B_shape, Z_shape}, expected_vals, Y_shape, false, true, true); + RunConvOp(attrs, {X, W, B, Z}, {X_shape, W_shape, B_shape, Z_shape}, expected_vals, Y_shape, false, true, true, true); } #endif diff --git a/onnxruntime/test/contrib_ops/gather_block_quantized_op_test.cc b/onnxruntime/test/contrib_ops/gather_block_quantized_op_test.cc index c4536fc56a22f..0dfe194e893e2 100644 --- a/onnxruntime/test/contrib_ops/gather_block_quantized_op_test.cc +++ b/onnxruntime/test/contrib_ops/gather_block_quantized_op_test.cc @@ -15,6 +15,27 @@ namespace onnxruntime { namespace test { +// When uint8_t data type is used GatherBlockQuantize applies MatMulNBit's conventions for storing the data. +// That is when no zero points are specified a default zero point of 8 is used. This convertor hence +// compensates for that by adding 8 to the data values, so that the outputs match the results that +// we be seen with non uint8_t data types. +template +void PackDataForUint8TypeIfNecessary(std::vector& data, std::vector& data_shape) { + if (!std::is_same_v) { + return; + } + // For uint8_t, we need to pack each pair of values (after adding 8) into a single uint8_t + std::vector packed_data; + for (size_t i = 0; i < data.size(); i += 2) { + int low_nibble = (data[i] + 8) & 0xF; + int high_nibble = ((i + 1) < data.size()) ? ((data[i + 1] + 8) & 0xF) : 0; + int packed = (high_nibble << 4) | low_nibble; + packed_data.push_back(packed); + } + data = packed_data; + data_shape[data_shape.size() - 1] = (data_shape[data_shape.size() - 1] + 1) / 2; +} + // Combinations: types, gather_axis, quantize_axis, block_size, indices, scale shape vs data shape template void RunGatherBlockQuantized(const std::vector& data, @@ -96,6 +117,7 @@ void Test_Fail_WithZeroPoints(int64_t gather_axis, 4, 5, 6, 7, -4, -3, -2, -1}; std::vector data_shape = {2, 3, 4}; + PackDataForUint8TypeIfNecessary(data, data_shape); std::vector indices = {1}; std::vector indices_shape = {1}; std::vector scales = {1.0f, 2.0f, 1.0f, 2.0f, 1.0f, 2.0f}; @@ -123,7 +145,6 @@ void Test_Fail_WithZeroPoints(int64_t gather_axis, TEST(GatherBlockQuantizedOpTest, UnsupportedTypes) { Test_Fail_WithZeroPoints(0, 2, 16); - Test_Fail_WithZeroPoints(0, 2, 16); Test_Fail_WithZeroPoints(0, 2, 16); Test_Fail_WithZeroPoints(0, 2, 16); Test_Fail_WithZeroPoints(0, 2, 16); @@ -134,21 +155,70 @@ TEST(GatherBlockQuantizedOpTest, UnsupportedTypes) { Test_Fail_WithZeroPoints(0, 2, 16); Test_Fail_WithZeroPoints(0, 2, 16); Test_Fail_WithZeroPoints(0, 2, 16); + Test_Fail_WithZeroPoints(0, 2, 16); +} + +template +void Test_Fail_WithoutZeroPoints(int64_t gather_axis, + int64_t quantize_axis, + int64_t block_size) { + std::vector data = {-8, -7, -6, -5, + -4, -3, -2, -1, + 0, 1, 2, 3, + 4, 5, 6, 7, + 4, 5, 6, 7, + -4, -3, -2, -1}; + std::vector data_shape = {2, 3, 4}; + PackDataForUint8TypeIfNecessary(data, data_shape); + std::vector indices = {1}; + std::vector indices_shape = {1}; + std::vector scales = {1.0f, 2.0f, 1.0f, 2.0f, 1.0f, 2.0f}; + std::vector scales_shape = {2, 3, 1}; + std::vector output = {8.f, 10.f, 12.f, 14.f, + 3.f, 4.f, 5.f, 6.f, + -6.f, -4.f, -2.f, 0.f}; + std::vector output_shape = {1, 3, 4}; + + RunGatherBlockQuantized(ToType(data), + data_shape, + ToType(indices), + indices_shape, + ToType(scales), + scales_shape, + {}, + gather_axis, + quantize_axis, + block_size, + ToType(output), + output_shape, + OpTester::ExpectResult::kExpectFailure); +} + +TEST(GatherBlockQuantizedOpTest, UnsupportedUInt8DataType) { + // T1 uint8_t with zero points is not yet supported. + Test_Fail_WithZeroPoints(0, 2, 16); + Test_Fail_WithZeroPoints(0, 2, 16); + // Gather on axis other than 0 is not supported with uint8_t + Test_Fail_WithoutZeroPoints(1, 2, 16); + Test_Fail_WithoutZeroPoints(1, 2, 16); } TEST(GatherBlockQuantizedOpTest, InvalidBlockSize) { Test_Fail_WithZeroPoints(0, 2, 8); Test_Fail_WithZeroPoints(0, 2, 17); + Test_Fail_WithZeroPoints(0, 2, 17); } TEST(GatherBlockQuantizedOpTest, InvalidGatherAxis) { Test_Fail_WithZeroPoints(3, 2, 16); Test_Fail_WithZeroPoints(-4, 2, 16); + Test_Fail_WithZeroPoints(-4, 2, 16); } TEST(GatherBlockQuantizedOpTest, InvalidQuantizeAxis) { Test_Fail_WithZeroPoints(0, 3, 16); Test_Fail_WithZeroPoints(0, -4, 16); + Test_Fail_WithZeroPoints(0, -4, 16); } template @@ -160,6 +230,7 @@ void Test_ShapeMismatch_WithZeroPoints() { 4, 5, 6, 7, -4, -3, -2, -1}; std::vector data_shape = {2, 3, 4}; + PackDataForUint8TypeIfNecessary(data, data_shape); std::vector indices = {1}; std::vector indices_shape = {1}; std::vector scales = {1.0f, 2.0f, 1.0f, 2.0f}; @@ -188,6 +259,7 @@ void Test_ShapeMismatch_WithZeroPoints() { TEST(GatherBlockQuantizedOpTest, ShapeMismatch) { Test_ShapeMismatch_WithZeroPoints(); Test_ShapeMismatch_WithZeroPoints(); + Test_ShapeMismatch_WithZeroPoints(); } template @@ -199,6 +271,7 @@ void Test_InvalidIndices_WithZeroPoints() { 4, 5, 6, 7, -4, -3, -2, -1}; std::vector data_shape = {2, 3, 4}; + PackDataForUint8TypeIfNecessary(data, data_shape); std::vector indices = {2}; std::vector indices_shape = {1}; std::vector scales = {1.0f, 2.0f, 1.0f, 2.0f, 1.0f, 2.0f}; @@ -227,6 +300,7 @@ void Test_InvalidIndices_WithZeroPoints() { TEST(GatherBlockQuantizedOpTest, InvalidIndices) { Test_InvalidIndices_WithZeroPoints(); Test_InvalidIndices_WithZeroPoints(); + Test_InvalidIndices_WithZeroPoints(); } template @@ -298,6 +372,7 @@ void Test_GatherAxis0_NoZeroPoints() { 4, 5, 6, 7, -4, -3, -2, -1}; std::vector data_shape = {2, 3, 4}; + PackDataForUint8TypeIfNecessary(data, data_shape); std::vector indices = {1}; std::vector indices_shape = {1}; std::vector scales = {1.0f, 2.0f, 1.0f, 2.0f, 1.0f, 2.0f}; @@ -340,6 +415,10 @@ TEST(GatherBlockQuantizedOpTest, GatherAxis0NoZeroPoints) { Test_GatherAxis0_NoZeroPoints(); Test_GatherAxis0_NoZeroPoints(); Test_GatherAxis0_NoZeroPoints(); + Test_GatherAxis0_NoZeroPoints(); + Test_GatherAxis0_NoZeroPoints(); + Test_GatherAxis0_NoZeroPoints(); + Test_GatherAxis0_NoZeroPoints(); } template diff --git a/onnxruntime/test/contrib_ops/layer_norm_op_test.cc b/onnxruntime/test/contrib_ops/layer_norm_op_test.cc index 4611dc9082734..e22445edc0f5b 100644 --- a/onnxruntime/test/contrib_ops/layer_norm_op_test.cc +++ b/onnxruntime/test/contrib_ops/layer_norm_op_test.cc @@ -404,7 +404,7 @@ TYPED_TEST(LayerNormTest, LayerNorm17_opset) { // Execution provider entry invalid. // when other EPs support layer-norm fp16, this test should be updated to include them. if (std::is_same::value) { -#if !defined(COREML_ENABLE_MLPROGRAM) +#if !defined(USE_COREML) return; #endif } diff --git a/onnxruntime/test/contrib_ops/matmul_4bits_test.cc b/onnxruntime/test/contrib_ops/matmul_4bits_test.cc index b1779ded4a675..81323cb51a887 100644 --- a/onnxruntime/test/contrib_ops/matmul_4bits_test.cc +++ b/onnxruntime/test/contrib_ops/matmul_4bits_test.cc @@ -389,6 +389,7 @@ TEST(MatMulNBits, Float32_Accuracy4) { TestMatMulNBitsTyped(); TestMatMulNBitsTyped(); TestMatMulNBitsTyped(); + TestMatMulNBitsTyped(); TestMatMulNBitsTyped(); TestMatMulNBitsTyped(); TestMatMulNBitsTyped(); @@ -458,6 +459,7 @@ TEST(MatMulNBits, Float16_Accuracy4) { TestMatMulNBitsTyped(); TestMatMulNBitsTyped(); TestMatMulNBitsTyped(); + TestMatMulNBitsTyped(); TestMatMulNBitsTyped(); TestMatMulNBitsTyped(); TestMatMulNBitsTyped(); @@ -528,8 +530,10 @@ TEST(MatMulNBits, Float16Cuda) { for (auto K : {16, 32, 64, 128, 256, 1024, 93, 1234}) { for (auto block_size : {16, 32, 64, 128}) { for (auto has_gidx : has_gidx_options) { -#ifdef USE_DML +#if defined(USE_DML) RunTest(M, N, K, block_size, 0, false, true, has_gidx, true, 0.04f); +#elif defined(USE_WEBGPU) + RunTest(M, N, K, block_size, 0, false, true, has_gidx, true, 0.03f); #else RunTest(M, N, K, block_size, 0, false, true, has_gidx); RunTest(M, N, K, block_size, 0, true, true, has_gidx, false); diff --git a/onnxruntime/test/contrib_ops/multihead_attention_op_test.cc b/onnxruntime/test/contrib_ops/multihead_attention_op_test.cc index ffdf69cc149b3..7c3dc617ffb12 100644 --- a/onnxruntime/test/contrib_ops/multihead_attention_op_test.cc +++ b/onnxruntime/test/contrib_ops/multihead_attention_op_test.cc @@ -25,27 +25,33 @@ namespace onnxruntime { namespace test { static void RunMultiHeadAttentionTest( - const std::vector& query_data, // query: [batch_size, sequence_length, hidden_size] - const std::vector& key_data, // key: [batch_size, kv_sequence_length, hidden_size] - const std::vector& value_data, // value: [batch_size, kv_sequence_length, v_hidden_size] - const std::vector& kv_data, // packed_kv: [batch_size, kv_sequence_length, num_heads, 2, head_size] - const std::vector& qkv_data, // packed_qkv: [batch_size, sequence_length, num_heads, 3, head_size] - const std::vector& bias_data, // bias: [hidden_size + hidden_size + v_hidden_size] or empty - const std::vector& attention_bias_data, // attention_bias: [1, num_heads, sequence_length, total_sequence_length] - const std::vector& past_key_data, // past_key: [batch_size, num_heads, kv_sequence_length, head_size] - const std::vector& past_value_data, // past_value: [batch_size, num_heads, kv_sequence_length, head_size] - const std::vector& present_key_data, // present_key: [batch_size, num_heads, total_sequence_length, head_size] - const std::vector& present_value_data, // present_value: [batch_size, num_heads, total_sequence_length, head_size] - const std::vector& key_padding_mask_data, // key_padding_mask: see below - AttentionMaskType mask_type, // 1 for [batch_size], 2 for [batch_size, kv_sequence_length] - const std::vector& output_data, // output: [batch_size, sequence_length, v_hidden_size] + const std::vector& query_data, // query: [batch_size, sequence_length, hidden_size] + const std::vector& key_data, // key: [batch_size, kv_sequence_length, hidden_size] + const std::vector& value_data, // value: [batch_size, kv_sequence_length, v_hidden_size] + const std::vector& kv_data, // packed_kv: [batch_size, kv_sequence_length, num_heads, 2, head_size] + const std::vector& qkv_data, // packed_qkv: [batch_size, sequence_length, num_heads, 3, head_size] + const std::vector& bias_data, // bias: [hidden_size + hidden_size + v_hidden_size] or empty + const std::vector& attention_bias_data, // attention_bias: [1, num_heads, sequence_length, total_sequence_length] + const std::vector& past_key_data, // past_key: [batch_size, num_heads, kv_sequence_length, head_size] + const std::vector& past_value_data, // past_value: [batch_size, num_heads, kv_sequence_length, head_size] + const std::vector& past_seq_len_data, // past_sequence_length: [1] or empty + const std::vector& cache_indir_data, // cache_indirection: [batch_size, num_beams, max_sequence_length] or empty + const std::vector& present_key_data, // present_key: [batch_size, num_heads, total_sequence_length, head_size] + const std::vector& present_value_data, // present_value: [batch_size, num_heads, total_sequence_length, head_size] + const std::vector& key_padding_mask_data, // key_padding_mask: see below + AttentionMaskType mask_type, // 1 for [batch_size], 2 for [batch_size, kv_sequence_length] + const std::vector& output_data, // output: [batch_size, sequence_length, v_hidden_size] + const std::vector& output_qk_data, // output_qk: [batch_size, num_heads, sequence_length, total_sequence_length] or empty int num_heads, int batch_size, int sequence_length, int kv_sequence_length, int hidden_size, int v_hidden_size, + int num_beams, + int max_sequence_length, bool is_static_kv = true, + bool buffer_share = false, bool use_float16 = false, bool disable_cpu = false, // some cases not supported in cpu right now. bool disable_cuda = false, @@ -53,6 +59,7 @@ static void RunMultiHeadAttentionTest( bool disable_rocm = DISABLE_ROCM, // not supported in rocm right now. bool disable_dml = false) { kv_sequence_length = (kv_sequence_length == 0 ? sequence_length : kv_sequence_length); + int past_sequence_length = (past_seq_len_data.size() == 0) ? 0 : past_seq_len_data[0]; int min_cuda_architecture = use_float16 ? 750 : 0; bool enable_cuda = HasCudaEnvironment(min_cuda_architecture) && !disable_cuda; @@ -81,15 +88,20 @@ static void RunMultiHeadAttentionTest( std::vector key_dims = {batch_size, is_static_kv ? kv_sequence_length : sequence_length, hidden_size}; std::vector value_dims = {batch_size, is_static_kv ? kv_sequence_length : sequence_length, v_hidden_size}; std::vector bias_dims = {hidden_size + hidden_size + v_hidden_size}; + // TODO(wy): Introduce past sequence length to avoid using kv_sequence_length. std::vector attention_bias_dims = {1, num_heads, sequence_length, past_key_data.size() ? sequence_length + kv_sequence_length : sequence_length}; - std::vector past_key_dims = {batch_size, num_heads, kv_sequence_length, hidden_size / num_heads}; + std::vector past_key_dims = {batch_size, num_heads, buffer_share ? max_sequence_length : kv_sequence_length, hidden_size / num_heads}; std::vector past_value_dims = past_key_dims; + std::vector past_seq_len_dims = {1}; + std::vector cache_indir_dims = {batch_size, num_beams, max_sequence_length}; + std::vector output_dims = {batch_size, sequence_length, v_hidden_size}; std::vector present_key_dims = - {batch_size, num_heads, is_static_kv ? kv_sequence_length : sequence_length + kv_sequence_length, hidden_size / num_heads}; + {batch_size, num_heads, buffer_share ? max_sequence_length : (is_static_kv ? kv_sequence_length : sequence_length + kv_sequence_length), hidden_size / num_heads}; std::vector present_value_dims = present_key_dims; + std::vector output_qk_dims = {batch_size, num_heads, sequence_length, is_static_kv ? kv_sequence_length : past_sequence_length + kv_sequence_length}; std::vector query = (qkv_data.size() > 0 ? qkv_data : query_data); std::vector key; @@ -164,6 +176,18 @@ static void RunMultiHeadAttentionTest( tester.AddOptionalInputEdge(); } + if (past_seq_len_data.size()) { + tester.AddInput("past_sequence_length", past_seq_len_dims, past_seq_len_data); + } else { + tester.AddOptionalInputEdge(); + } + + if (cache_indir_data.size()) { + tester.AddInput("cache_indirection", cache_indir_dims, cache_indir_data); + } else { + tester.AddOptionalInputEdge(); + } + constexpr float rel_error = 0.0f; constexpr float abs_error = 0.05f; tester.AddOutput("output", output_dims, ToFloat16(output_data), /*sort*/ false, rel_error, abs_error); @@ -179,6 +203,12 @@ static void RunMultiHeadAttentionTest( } else { tester.AddOptionalOutputEdge(); } + + if (output_qk_data.size()) { + tester.AddOutput("output_qk", output_qk_dims, ToFloat16(output_qk_data), /*sort*/ false, rel_error, abs_error); + } else { + tester.AddOptionalOutputEdge(); + } } else { tester.AddInput("query", query_dims, query); @@ -228,6 +258,18 @@ static void RunMultiHeadAttentionTest( tester.AddOptionalInputEdge(); } + if (past_seq_len_data.size()) { + tester.AddInput("past_sequence_length", past_seq_len_dims, past_seq_len_data); + } else { + tester.AddOptionalInputEdge(); + } + + if (cache_indir_data.size()) { + tester.AddInput("cache_indirection", cache_indir_dims, cache_indir_data); + } else { + tester.AddOptionalInputEdge(); + } + constexpr float rel_error = 0.0f; constexpr float abs_error = 0.02f; tester.AddOutput("output", output_dims, output_data, /*sort*/ false, rel_error, abs_error); @@ -243,6 +285,12 @@ static void RunMultiHeadAttentionTest( } else { tester.AddOptionalOutputEdge(); } + + if (output_qk_data.size()) { + tester.AddOutput("output_qk", output_qk_dims, output_qk_data, /*sort*/ false, rel_error, abs_error); + } else { + tester.AddOptionalOutputEdge(); + } } if (enable_cuda) { @@ -278,29 +326,35 @@ static void RunMultiHeadAttentionTest( } static void RunMultiHeadAttentionKernel( - const std::vector& query_data, // query: [batch_size, sequence_length, hidden_size] - const std::vector& key_data, // key: [batch_size, kv_sequence_length, hidden_size] - const std::vector& value_data, // value: [batch_size, kv_sequence_length, v_hidden_size] - const std::vector& kv_data, // packed_kv: [batch_size, kv_sequence_length, num_heads, 2, head_size] - const std::vector& qkv_data, // packed_qkv: [batch_size, sequence_length, num_heads, 3, head_size] - const std::vector& bias_data, // bias: [hidden_size + hidden_size + v_hidden_size] - const std::vector& attention_bias_data, // attention_bias: [1, num_heads, sequence_length, total_sequence_length] - const std::vector& past_key_data, // past_key: [batch_size, num_heads, kv_sequence_length, head_size] - const std::vector& past_value_data, // past_value: [batch_size, num_heads, kv_sequence_length, head_size] - const std::vector& present_key_data, // present_key: [batch_size, num_heads, total_sequence_length, head_size] - const std::vector& present_value_data, // present_value: [batch_size, num_heads, total_sequence_length, head_size] - const std::vector& key_padding_mask_data, // key_padding_mask: see below - AttentionMaskType mask_type, // 1 for [batch_size], 2 for [batch_size, kv_sequence_length] - const std::vector& output_data, // output: [batch_size, sequence_length, v_hidden_size] + const std::vector& query_data, // query: [batch_size, sequence_length, hidden_size] + const std::vector& key_data, // key: [batch_size, kv_sequence_length, hidden_size] + const std::vector& value_data, // value: [batch_size, kv_sequence_length, v_hidden_size] + const std::vector& kv_data, // packed_kv: [batch_size, kv_sequence_length, num_heads, 2, head_size] + const std::vector& qkv_data, // packed_qkv: [batch_size, sequence_length, num_heads, 3, head_size] + const std::vector& bias_data, // bias: [hidden_size + hidden_size + v_hidden_size] + const std::vector& attention_bias_data, // attention_bias: [1, num_heads, sequence_length, total_sequence_length] + const std::vector& past_key_data, // past_key: [batch_size, num_heads, kv_sequence_length, head_size] + const std::vector& past_value_data, // past_value: [batch_size, num_heads, kv_sequence_length, head_size] + const std::vector& past_seq_len_data, // past_sequence_length: [1] + const std::vector& cache_indir_data, // cache_indirection: [batch_size, num_beams, max_sequence_length] + const std::vector& present_key_data, // present_key: [batch_size, num_heads, total_sequence_length, head_size] + const std::vector& present_value_data, // present_value: [batch_size, num_heads, total_sequence_length, head_size] + const std::vector& key_padding_mask_data, // key_padding_mask: see below + AttentionMaskType mask_type, // 1 for [batch_size], 2 for [batch_size, kv_sequence_length] + const std::vector& output_data, // output: [batch_size, sequence_length, v_hidden_size] + const std::vector& output_qk_data, // output_qk: [batch_size, num_heads, sequence_length, total_sequence_length] + AttentionKernelType kernel_type, int num_heads, int batch_size, int sequence_length, int kv_sequence_length, int hidden_size, int v_hidden_size, - AttentionKernelType kernel_type, - bool use_float16 = true, + int num_beams, + int max_sequence_length, bool is_static_kv = true, + bool buffer_share = false, + bool use_float16 = true, bool disable_cpu = false, // some cases not supported in cpu right now. bool disable_cuda = false, bool disable_webgpu = false, @@ -316,10 +370,11 @@ static void RunMultiHeadAttentionKernel( {onnxruntime::contrib::attention::kDisableMemoryEfficientAttention, "0"}}}; RunMultiHeadAttentionTest( query_data, key_data, value_data, kv_data, qkv_data, bias_data, attention_bias_data, - past_key_data, past_value_data, present_key_data, present_value_data, key_padding_mask_data, - mask_type, output_data, num_heads, batch_size, sequence_length, kv_sequence_length, - hidden_size, v_hidden_size, is_static_kv, use_float16, disable_cpu, disable_cuda, disable_webgpu, - disable_rocm, disable_dml); + past_key_data, past_value_data, past_seq_len_data, cache_indir_data, + present_key_data, present_value_data, key_padding_mask_data, mask_type, + output_data, output_qk_data, num_heads, batch_size, sequence_length, kv_sequence_length, + hidden_size, v_hidden_size, num_beams, max_sequence_length, is_static_kv, buffer_share, use_float16, + disable_cpu, disable_cuda, disable_webgpu, disable_rocm, disable_dml); return; } @@ -333,10 +388,11 @@ static void RunMultiHeadAttentionKernel( {onnxruntime::contrib::attention::kDisableMemoryEfficientAttention, "1"}}}; RunMultiHeadAttentionTest( query_data, key_data, value_data, kv_data, qkv_data, bias_data, attention_bias_data, - past_key_data, past_value_data, present_key_data, present_value_data, key_padding_mask_data, - mask_type, output_data, num_heads, batch_size, sequence_length, kv_sequence_length, - hidden_size, v_hidden_size, is_static_kv, use_float16, disable_cpu, disable_cuda, disable_webgpu, - disable_rocm, disable_dml); + past_key_data, past_value_data, past_seq_len_data, cache_indir_data, + present_key_data, present_value_data, key_padding_mask_data, mask_type, + output_data, output_qk_data, num_heads, batch_size, sequence_length, kv_sequence_length, + hidden_size, v_hidden_size, num_beams, max_sequence_length, is_static_kv, buffer_share, use_float16, + disable_cpu, disable_cuda, disable_webgpu, disable_rocm, disable_dml); return; } @@ -350,10 +406,11 @@ static void RunMultiHeadAttentionKernel( {onnxruntime::contrib::attention::kDisableMemoryEfficientAttention, "1"}}}; RunMultiHeadAttentionTest( query_data, key_data, value_data, kv_data, qkv_data, bias_data, attention_bias_data, - past_key_data, past_value_data, present_key_data, present_value_data, key_padding_mask_data, - mask_type, output_data, num_heads, batch_size, sequence_length, kv_sequence_length, - hidden_size, v_hidden_size, is_static_kv, use_float16, disable_cpu, disable_cuda, disable_webgpu, - disable_rocm, disable_dml); + past_key_data, past_value_data, past_seq_len_data, cache_indir_data, + present_key_data, present_value_data, key_padding_mask_data, mask_type, + output_data, output_qk_data, num_heads, batch_size, sequence_length, kv_sequence_length, + hidden_size, v_hidden_size, num_beams, max_sequence_length, is_static_kv, buffer_share, use_float16, + disable_cpu, disable_cuda, disable_webgpu, disable_rocm, disable_dml); return; } @@ -368,10 +425,11 @@ static void RunMultiHeadAttentionKernel( {onnxruntime::contrib::attention::kDisableMemoryEfficientAttention, "0"}}}; RunMultiHeadAttentionTest( query_data, key_data, value_data, kv_data, qkv_data, bias_data, attention_bias_data, - past_key_data, past_value_data, present_key_data, present_value_data, key_padding_mask_data, - mask_type, output_data, num_heads, batch_size, sequence_length, kv_sequence_length, - hidden_size, v_hidden_size, is_static_kv, use_float16, disable_cpu, disable_cuda, disable_webgpu, - disable_rocm, disable_dml); + past_key_data, past_value_data, past_seq_len_data, cache_indir_data, + present_key_data, present_value_data, key_padding_mask_data, mask_type, + output_data, output_qk_data, num_heads, batch_size, sequence_length, kv_sequence_length, + hidden_size, v_hidden_size, num_beams, max_sequence_length, is_static_kv, buffer_share, use_float16, + disable_cpu, disable_cuda, disable_webgpu, disable_rocm, disable_dml); return; } #endif @@ -387,10 +445,11 @@ static void RunMultiHeadAttentionKernel( {onnxruntime::contrib::attention::kDisableMemoryEfficientAttention, "1"}}}; RunMultiHeadAttentionTest( query_data, key_data, value_data, kv_data, qkv_data, bias_data, attention_bias_data, - past_key_data, past_value_data, present_key_data, present_value_data, key_padding_mask_data, - mask_type, output_data, num_heads, batch_size, sequence_length, kv_sequence_length, - hidden_size, v_hidden_size, is_static_kv, use_float16, disable_cpu, disable_cuda, disable_webgpu, - disable_rocm, disable_dml); + past_key_data, past_value_data, past_seq_len_data, cache_indir_data, + present_key_data, present_value_data, key_padding_mask_data, mask_type, + output_data, output_qk_data, num_heads, batch_size, sequence_length, kv_sequence_length, + hidden_size, v_hidden_size, num_beams, max_sequence_length, is_static_kv, buffer_share, use_float16, + disable_cpu, disable_cuda, disable_webgpu, disable_rocm, disable_dml); } if (kernel_type == AttentionKernelType::AttentionKernel_CudnnFlashAttention) { @@ -404,10 +463,11 @@ static void RunMultiHeadAttentionKernel( {onnxruntime::contrib::attention::kDisableMemoryEfficientAttention, "1"}}}; RunMultiHeadAttentionTest( query_data, key_data, value_data, kv_data, qkv_data, bias_data, attention_bias_data, - past_key_data, past_value_data, present_key_data, present_value_data, key_padding_mask_data, - mask_type, output_data, num_heads, batch_size, sequence_length, kv_sequence_length, - hidden_size, v_hidden_size, is_static_kv, use_float16, disable_cpu, disable_cuda, disable_webgpu, - disable_rocm, disable_dml); + past_key_data, past_value_data, past_seq_len_data, cache_indir_data, + present_key_data, present_value_data, key_padding_mask_data, mask_type, + output_data, output_qk_data, num_heads, batch_size, sequence_length, kv_sequence_length, + hidden_size, v_hidden_size, num_beams, max_sequence_length, is_static_kv, buffer_share, use_float16, + disable_cpu, disable_cuda, disable_webgpu, disable_rocm, disable_dml); } } @@ -416,6 +476,8 @@ enum RunMultiHeadAttentionTestToggles : uint32_t { DISABLE_CPU = 1 << 0, DISABLE_CUDA = 1 << 1, DISABLE_WEBGPU = 1 << 2, + DISABLE_ROCM_MHA = 1 << 3, + DISABLE_DML = 1 << 4, }; inline RunMultiHeadAttentionTestToggles operator|(RunMultiHeadAttentionTestToggles a, RunMultiHeadAttentionTestToggles b) { return static_cast(static_cast(a) | static_cast(b)); @@ -429,6 +491,8 @@ static void RunMultiHeadAttentionTests(AttentionTestData& data, bool disable_cpu = toggles & DISABLE_CPU; bool disable_cuda = toggles & DISABLE_CUDA; bool disable_webgpu = toggles & DISABLE_WEBGPU; + bool disable_rocm = toggles & DISABLE_ROCM_MHA; + bool disable_dml = toggles & DISABLE_DML; if (data.fp32_output_data.size() > 0) { constexpr bool use_float16 = false; @@ -437,10 +501,11 @@ static void RunMultiHeadAttentionTests(AttentionTestData& data, if (!SkipAttentionKernel(data, kernel_type)) { RunMultiHeadAttentionKernel( data.query_data, data.key_data, data.value_data, data.kv_data, data.qkv_data, data.bias_data, - data.attention_bias_data, data.past_key_data, data.past_value_data, data.present_key_data, - data.present_value_data, data.key_padding_mask_data, data.mask_type, data.fp32_output_data, - data.num_heads, data.batch_size, data.sequence_length, data.kv_sequence_length, data.hidden_size, - data.v_hidden_size, kernel_type, use_float16, data.is_static_kv, disable_cpu, disable_cuda, disable_webgpu); + data.attention_bias_data, data.past_key_data, data.past_value_data, data.past_seq_len_data, data.cache_indir_data, + data.present_key_data, data.present_value_data, data.key_padding_mask_data, data.mask_type, data.fp32_output_data, + data.fp32_output_qk_data, kernel_type, data.num_heads, data.batch_size, data.sequence_length, data.kv_sequence_length, data.hidden_size, + data.v_hidden_size, data.num_beams, data.max_sequence_length, data.is_static_kv, data.buffer_share, use_float16, + disable_cpu, disable_cuda, disable_webgpu, disable_rocm, disable_dml); } #if USE_MEMORY_EFFICIENT_ATTENTION @@ -450,10 +515,11 @@ static void RunMultiHeadAttentionTests(AttentionTestData& data, if (!SkipAttentionKernel(data, kernel_type)) { RunMultiHeadAttentionKernel( data.query_data, data.key_data, data.value_data, data.kv_data, data.qkv_data, data.bias_data, - data.attention_bias_data, data.past_key_data, data.past_value_data, data.present_key_data, - data.present_value_data, data.key_padding_mask_data, data.mask_type, data.fp32_output_data, - data.num_heads, data.batch_size, data.sequence_length, data.kv_sequence_length, data.hidden_size, - data.v_hidden_size, kernel_type, use_float16, data.is_static_kv, disable_cpu, disable_cuda, disable_webgpu); + data.attention_bias_data, data.past_key_data, data.past_value_data, data.past_seq_len_data, data.cache_indir_data, + data.present_key_data, data.present_value_data, data.key_padding_mask_data, data.mask_type, data.fp32_output_data, + data.fp32_output_qk_data, kernel_type, data.num_heads, data.batch_size, data.sequence_length, data.kv_sequence_length, data.hidden_size, + data.v_hidden_size, data.num_beams, data.max_sequence_length, data.is_static_kv, data.buffer_share, use_float16, + disable_cpu, disable_cuda, disable_webgpu, disable_rocm, disable_dml); } } #endif @@ -461,10 +527,11 @@ static void RunMultiHeadAttentionTests(AttentionTestData& data, kernel_type = AttentionKernelType::AttentionKernel_Default; RunMultiHeadAttentionKernel( data.query_data, data.key_data, data.value_data, data.kv_data, data.qkv_data, data.bias_data, - data.attention_bias_data, data.past_key_data, data.past_value_data, data.present_key_data, - data.present_value_data, data.key_padding_mask_data, data.mask_type, data.fp32_output_data, - data.num_heads, data.batch_size, data.sequence_length, data.kv_sequence_length, data.hidden_size, - data.v_hidden_size, kernel_type, use_float16, data.is_static_kv, disable_cpu, disable_cuda, disable_webgpu); + data.attention_bias_data, data.past_key_data, data.past_value_data, data.past_seq_len_data, data.cache_indir_data, + data.present_key_data, data.present_value_data, data.key_padding_mask_data, data.mask_type, data.fp32_output_data, + data.fp32_output_qk_data, kernel_type, data.num_heads, data.batch_size, data.sequence_length, data.kv_sequence_length, data.hidden_size, + data.v_hidden_size, data.num_beams, data.max_sequence_length, data.is_static_kv, data.buffer_share, use_float16, + disable_cpu, disable_cuda, disable_webgpu, disable_rocm, disable_dml); } if (data.fp16_output_data.size() > 0) { @@ -473,20 +540,22 @@ static void RunMultiHeadAttentionTests(AttentionTestData& data, if (!SkipAttentionKernel(data, kernel_type)) { RunMultiHeadAttentionKernel( data.query_data, data.key_data, data.value_data, data.kv_data, data.qkv_data, data.bias_data, - data.attention_bias_data, data.past_key_data, data.past_value_data, data.present_key_data, - data.present_value_data, data.key_padding_mask_data, data.mask_type, data.fp16_output_data, - data.num_heads, data.batch_size, data.sequence_length, data.kv_sequence_length, data.hidden_size, - data.v_hidden_size, kernel_type, use_float16, data.is_static_kv, disable_cpu, disable_cuda, disable_webgpu); + data.attention_bias_data, data.past_key_data, data.past_value_data, data.past_seq_len_data, data.cache_indir_data, + data.present_key_data, data.present_value_data, data.key_padding_mask_data, data.mask_type, data.fp16_output_data, + data.fp16_output_qk_data, kernel_type, data.num_heads, data.batch_size, data.sequence_length, data.kv_sequence_length, data.hidden_size, + data.v_hidden_size, data.num_beams, data.max_sequence_length, data.is_static_kv, data.buffer_share, use_float16, + disable_cpu, disable_cuda, disable_webgpu, disable_rocm, disable_dml); } kernel_type = AttentionKernelType::AttentionKernel_TrtFusedAttention; if (!SkipAttentionKernel(data, kernel_type)) { RunMultiHeadAttentionKernel( data.query_data, data.key_data, data.value_data, data.kv_data, data.qkv_data, data.bias_data, - data.attention_bias_data, data.past_key_data, data.past_value_data, data.present_key_data, - data.present_value_data, data.key_padding_mask_data, data.mask_type, data.fp16_output_data, - data.num_heads, data.batch_size, data.sequence_length, data.kv_sequence_length, data.hidden_size, - data.v_hidden_size, kernel_type, use_float16, data.is_static_kv, disable_cpu, disable_cuda, disable_webgpu); + data.attention_bias_data, data.past_key_data, data.past_value_data, data.past_seq_len_data, data.cache_indir_data, + data.present_key_data, data.present_value_data, data.key_padding_mask_data, data.mask_type, data.fp16_output_data, + data.fp16_output_qk_data, kernel_type, data.num_heads, data.batch_size, data.sequence_length, data.kv_sequence_length, data.hidden_size, + data.v_hidden_size, data.num_beams, data.max_sequence_length, data.is_static_kv, data.buffer_share, use_float16, + disable_cpu, disable_cuda, disable_webgpu, disable_rocm, disable_dml); } #if USE_MEMORY_EFFICIENT_ATTENTION @@ -494,10 +563,11 @@ static void RunMultiHeadAttentionTests(AttentionTestData& data, if (!SkipAttentionKernel(data, kernel_type)) { RunMultiHeadAttentionKernel( data.query_data, data.key_data, data.value_data, data.kv_data, data.qkv_data, data.bias_data, - data.attention_bias_data, data.past_key_data, data.past_value_data, data.present_key_data, - data.present_value_data, data.key_padding_mask_data, data.mask_type, data.fp16_output_data, - data.num_heads, data.batch_size, data.sequence_length, data.kv_sequence_length, data.hidden_size, - data.v_hidden_size, kernel_type, use_float16, data.is_static_kv, disable_cpu, disable_cuda, disable_webgpu); + data.attention_bias_data, data.past_key_data, data.past_value_data, data.past_seq_len_data, data.cache_indir_data, + data.present_key_data, data.present_value_data, data.key_padding_mask_data, data.mask_type, data.fp16_output_data, + data.fp16_output_qk_data, kernel_type, data.num_heads, data.batch_size, data.sequence_length, data.kv_sequence_length, data.hidden_size, + data.v_hidden_size, data.num_beams, data.max_sequence_length, data.is_static_kv, data.buffer_share, use_float16, + disable_cpu, disable_cuda, disable_webgpu, disable_rocm, disable_dml); } #endif @@ -505,19 +575,21 @@ static void RunMultiHeadAttentionTests(AttentionTestData& data, if (!SkipAttentionKernel(data, kernel_type)) { RunMultiHeadAttentionKernel( data.query_data, data.key_data, data.value_data, data.kv_data, data.qkv_data, data.bias_data, - data.attention_bias_data, data.past_key_data, data.past_value_data, data.present_key_data, - data.present_value_data, data.key_padding_mask_data, data.mask_type, data.fp16_output_data, - data.num_heads, data.batch_size, data.sequence_length, data.kv_sequence_length, data.hidden_size, - data.v_hidden_size, kernel_type, use_float16, data.is_static_kv, disable_cpu, disable_cuda, disable_webgpu); + data.attention_bias_data, data.past_key_data, data.past_value_data, data.past_seq_len_data, data.cache_indir_data, + data.present_key_data, data.present_value_data, data.key_padding_mask_data, data.mask_type, data.fp16_output_data, + data.fp16_output_qk_data, kernel_type, data.num_heads, data.batch_size, data.sequence_length, data.kv_sequence_length, data.hidden_size, + data.v_hidden_size, data.num_beams, data.max_sequence_length, data.is_static_kv, data.buffer_share, use_float16, + disable_cpu, disable_cuda, disable_webgpu, disable_rocm, disable_dml); } kernel_type = AttentionKernelType::AttentionKernel_Default; RunMultiHeadAttentionKernel( data.query_data, data.key_data, data.value_data, data.kv_data, data.qkv_data, data.bias_data, - data.attention_bias_data, data.past_key_data, data.past_value_data, data.present_key_data, - data.present_value_data, data.key_padding_mask_data, data.mask_type, data.fp16_output_data, - data.num_heads, data.batch_size, data.sequence_length, data.kv_sequence_length, data.hidden_size, - data.v_hidden_size, kernel_type, use_float16, data.is_static_kv, disable_cpu, disable_cuda, disable_webgpu); + data.attention_bias_data, data.past_key_data, data.past_value_data, data.past_seq_len_data, data.cache_indir_data, + data.present_key_data, data.present_value_data, data.key_padding_mask_data, data.mask_type, data.fp16_output_data, + data.fp16_output_qk_data, kernel_type, data.num_heads, data.batch_size, data.sequence_length, data.kv_sequence_length, data.hidden_size, + data.v_hidden_size, data.num_beams, data.max_sequence_length, data.is_static_kv, data.buffer_share, use_float16, + disable_cpu, disable_cuda, disable_webgpu, disable_rocm, disable_dml); } } @@ -666,5 +738,23 @@ TEST(MultiHeadAttentionTest, DISABLED_CrossAttention_WithPastPassedInDirectly_No RunMultiHeadAttentionTests(data); } +TEST(MultiHeadAttentionTest, SelfAttention_PastPresentBufferShare_UsingDMMHAInsideMHA) { + // Whisper decoder self attention with past_kv, present_kv, buffer sharing enabled, mask, and bias + // Used in decoder-with-past's self-attention layers + // For CUDA, K caches are transposed and reshaped from 4D to 5D for DecoderMaskedMultiHeadAttention + // See onnxruntime/core/graph/contrib_ops/bert_defs.cc for more details + AttentionTestData data; + GetSelfAttention_PastPresentBufferShare_UsingDMMHAInsideMHA(data); + RunMultiHeadAttentionTests(data, DISABLE_CPU | DISABLE_ROCM_MHA | DISABLE_WEBGPU | DISABLE_DML); +} + +TEST(MultiHeadAttentionTest, CrossAttention_DiffSequenceLengths_UsingDMMHAInsideMHA) { + // Whisper decoder cross attention with past_kv used directly as K and V, no mask, and bias + // Used in decoder-with-past's cross-attention layers + AttentionTestData data; + GetCrossAttention_DiffSequenceLengths_UsingDMMHAInsideMHA(data); + RunMultiHeadAttentionTests(data, DISABLE_CPU | DISABLE_ROCM_MHA | DISABLE_WEBGPU | DISABLE_DML); +} + } // namespace test } // namespace onnxruntime diff --git a/onnxruntime/test/contrib_ops/rotary_embedding_op_test.cc b/onnxruntime/test/contrib_ops/rotary_embedding_op_test.cc index 0e964cf64fbbd..625c5ec35e20d 100644 --- a/onnxruntime/test/contrib_ops/rotary_embedding_op_test.cc +++ b/onnxruntime/test/contrib_ops/rotary_embedding_op_test.cc @@ -86,44 +86,48 @@ static void RunTest( return; } - OpTester test(op_type.c_str(), 1, onnxruntime::kMSDomain); - test.AddAttribute("interleaved", interleaved); - - if (rotary_embedding_dim > 0) { - test.AddAttribute("rotary_embedding_dim", rotary_embedding_dim); - test.AddAttribute("num_heads", num_heads); - } - - if (rotary_embedding_dim > 0) { - test.AddAttribute("is_packed_batching", is_packed_batching); + for (auto& ep : execution_providers) { + OpTester test(op_type.c_str(), 1, onnxruntime::kMSDomain); + test.AddAttribute("interleaved", interleaved); + + if (rotary_embedding_dim > 0) { + test.AddAttribute("rotary_embedding_dim", rotary_embedding_dim); + test.AddAttribute("num_heads", num_heads); + } + + if (rotary_embedding_dim > 0) { + test.AddAttribute("is_packed_batching", is_packed_batching); + } + + if (tensor_type == TensorType::kFloat) { + test.AddInput("input", input_dims, input_data); + test.AddInput("position_ids", pos_dims, position_ids); + test.AddInput("cos_cache", cache_dims, cos_cache); + test.AddInput("sin_cache", cache_dims, sin_cache); + test.AddOutput("output", input_dims, output_data); + } else if (tensor_type == TensorType::kFloat16) { + test.AddInput("input", input_dims, ToFloat16(input_data)); + test.AddInput("position_ids", pos_dims, position_ids); + test.AddInput("cos_cache", cache_dims, ToFloat16(cos_cache)); + test.AddInput("sin_cache", cache_dims, ToFloat16(sin_cache)); + test.AddOutput("output", input_dims, ToFloat16(output_data)); + } else { + test.AddInput("input", input_dims, FloatsToBFloat16s(input_data)); + test.AddInput("position_ids", pos_dims, position_ids); + test.AddInput("cos_cache", cache_dims, FloatsToBFloat16s(cos_cache)); + test.AddInput("sin_cache", cache_dims, FloatsToBFloat16s(sin_cache)); + test.AddOutput("output", input_dims, FloatsToBFloat16s(output_data)); + } + if (tensor_type == TensorType::kBFloat16) { + test.SetOutputAbsErr("output", 0.03f); + } else { + test.SetOutputAbsErr("output", 0.002f); + } + + std::vector> test_execution_providers; + test_execution_providers.push_back(std::move(ep)); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &test_execution_providers); } - - if (tensor_type == TensorType::kFloat) { - test.AddInput("input", input_dims, input_data); - test.AddInput("position_ids", pos_dims, position_ids); - test.AddInput("cos_cache", cache_dims, cos_cache); - test.AddInput("sin_cache", cache_dims, sin_cache); - test.AddOutput("output", input_dims, output_data); - } else if (tensor_type == TensorType::kFloat16) { - test.AddInput("input", input_dims, ToFloat16(input_data)); - test.AddInput("position_ids", pos_dims, position_ids); - test.AddInput("cos_cache", cache_dims, ToFloat16(cos_cache)); - test.AddInput("sin_cache", cache_dims, ToFloat16(sin_cache)); - test.AddOutput("output", input_dims, ToFloat16(output_data)); - } else { - test.AddInput("input", input_dims, FloatsToBFloat16s(input_data)); - test.AddInput("position_ids", pos_dims, position_ids); - test.AddInput("cos_cache", cache_dims, FloatsToBFloat16s(cos_cache)); - test.AddInput("sin_cache", cache_dims, FloatsToBFloat16s(sin_cache)); - test.AddOutput("output", input_dims, FloatsToBFloat16s(output_data)); - } - if (tensor_type == TensorType::kBFloat16) { - test.SetOutputAbsErr("output", 0.03f); - } else { - test.SetOutputAbsErr("output", 0.002f); - } - - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &execution_providers); } static void RunTests(const std::vector& input_data, diff --git a/onnxruntime/test/ep_weight_sharing_ctx_gen/README.md b/onnxruntime/test/ep_weight_sharing_ctx_gen/README.md new file mode 100644 index 0000000000000..66b8467bda335 --- /dev/null +++ b/onnxruntime/test/ep_weight_sharing_ctx_gen/README.md @@ -0,0 +1,38 @@ +# ONNXRuntime EP Context Model Generation with Weight Sharing + +[EP context with weight sharing design doc](https://onnxruntime.ai/docs/execution-providers/EP-Context-Design.html#epcontext-with-weight-sharing) + +OnnxRuntime provides the ep_weight_sharing_ctx_gen tool to automate the weight-sharing workflow. This tool handles the entire process. This tool is specifically designed for weight sharing scenarios, streamlining the EPContext model generation process. + +Example command line: + +``` +ep_weight_sharing_ctx_gen [options...] model1_path,model2_path + +Example: ./ep_weight_sharing_ctx_gen -e qnn -i "soc_model|60 htp_graph_finalization_optimization_mode|3" -C "ep.context_node_name_prefix|_part1" ./model1.onnx,./model2.onnx + +Options: + -e [qnn|tensorrt|openvino|vitisai]: Specifies the compile based provider 'qnn', 'tensorrt', 'openvino', 'vitisai'. Default: 'qnn'. + -v: Show verbose information. + -C: Specify session configuration entries as key-value pairs: -C "| |" + Refer to onnxruntime_session_options_config_keys.h for valid keys and values. + Force ep.context_enable to 1 and ep.context_embed_mode to 0. Change ep.context_file_path is not allowed. + [Example] -C "ep.context_node_name_prefix|_part1" + -i: Specify EP specific runtime options as key value pairs. Different runtime options available are: + [Usage]: -i '| |' + + [QNN only] [backend_type]: QNN backend type. E.g., 'cpu', 'htp'. Mutually exclusive with 'backend_path'. + [QNN only] [backend_path]: QNN backend path. E.g., '/folderpath/libQnnHtp.so', '/winfolderpath/QnnHtp.dll'. Mutually exclusive with 'backend_type'. + [QNN only] [vtcm_mb]: QNN VTCM size in MB. default to 0(not set). + [QNN only] [htp_graph_finalization_optimization_mode]: QNN graph finalization optimization mode, options: '0', '1', '2', '3', default is '0'. + [QNN only] [soc_model]: The SoC Model number. Refer to QNN SDK documentation for specific values. Defaults to '0' (unknown). + [QNN only] [htp_arch]: The minimum HTP architecture. The driver will use ops compatible with this architecture. eg: '0', '68', '69', '73', '75'. Defaults to '0' (none). + [QNN only] [enable_htp_fp16_precision]: Enable the HTP_FP16 precision so that the float32 model will be inferenced with fp16 precision. + Otherwise, it will be fp32 precision. Works for float32 model for HTP backend. Defaults to '1' (with FP16 precision.). + [QNN only] [offload_graph_io_quantization]: Offload graph input quantization and graph output dequantization to another EP (typically CPU EP). + Defaults to '1' (another EP (typically CPU EP) handles the graph I/O quantization and dequantization). + [QNN only] [enable_htp_spill_fill_buffer]: Enable HTP spill file buffer, used while generating QNN context binary. + [Example] -i "vtcm_mb|8 htp_arch|73" + + -h: help +``` diff --git a/onnxruntime/test/qnn_ctx_gen/command_args_parser.cc b/onnxruntime/test/ep_weight_sharing_ctx_gen/command_args_parser.cc similarity index 60% rename from onnxruntime/test/qnn_ctx_gen/command_args_parser.cc rename to onnxruntime/test/ep_weight_sharing_ctx_gen/command_args_parser.cc index 24c343c7b9541..cecf5575d42a5 100644 --- a/onnxruntime/test/qnn_ctx_gen/command_args_parser.cc +++ b/onnxruntime/test/ep_weight_sharing_ctx_gen/command_args_parser.cc @@ -1,5 +1,4 @@ // Copyright (c) Microsoft Corporation. All rights reserved. -// Copyright (c) 2023 NVIDIA Corporation. // Licensed under the MIT License. #include "command_args_parser.h" @@ -29,28 +28,32 @@ namespace qnnctxgen { /*static*/ void CommandLineParser::ShowUsage() { printf( - "onnxruntime_qnn_ctx_gen [options...] model1_path,model2_path\n" - "Example: ./onnxruntime_qnn_ctx_gen -i \"soc_model|60 htp_graph_finalization_optimization_mode|3\" -C \"ep.context_node_name_prefix|_part1\" ./model1.onnx,./model2.onnx\n" + "%s", + "ep_weight_sharing_ctx_gen [options...] model1_path,model2_path\n" + "\n" + "Example: ./ep_weight_sharing_ctx_gen -e qnn -i \"soc_model|60 htp_graph_finalization_optimization_mode|3\" -C \"ep.context_node_name_prefix|_part1\" ./model1.onnx,./model2.onnx\n" + "\n" "Options:\n" + "\t-e [qnn|tensorrt|openvino|vitisai]: Specifies the compile based provider 'qnn', 'tensorrt', 'openvino', 'vitisai'. Default: 'qnn'.\n" "\t-v: Show verbose information.\n" "\t-C: Specify session configuration entries as key-value pairs: -C \"| |\" \n" "\t Refer to onnxruntime_session_options_config_keys.h for valid keys and values. \n" - "\t Force ep.context_enable to 1 and ep.context_embed_mode to 0. Change ep.context_file_path is not allowed." + "\t Force ep.context_enable to 1 and ep.context_embed_mode to 0. Change ep.context_file_path is not allowed.\n" "\t [Example] -C \"ep.context_node_name_prefix|_part1\" \n" - "\t-i: Specify QNN EP specific runtime options as key value pairs. Different runtime options available are: \n" + "\t-i: Specify EP specific runtime options as key value pairs. Different runtime options available are: \n" "\t [Usage]: -i '| |'\n" "\n" - "\t [backend_path]: QNN backend path. e.g '/folderpath/libQnnHtp.so', '/winfolderpath/QnnHtp.dll'. default to HTP backend\n" - "\t [vtcm_mb]: QNN VTCM size in MB. default to 0(not set).\n" - "\t [htp_graph_finalization_optimization_mode]: QNN graph finalization optimization mode, options: '0', '1', '2', '3', default is '0'.\n" - "\t [soc_model]: The SoC Model number. Refer to QNN SDK documentation for specific values. Defaults to '0' (unknown). \n" - "\t [htp_arch]: The minimum HTP architecture. The driver will use ops compatible with this architecture. eg: '0', '68', '69', '73', '75'. Defaults to '0' (none). \n" - "\t [enable_htp_fp16_precision]: Enable the HTP_FP16 precision so that the float32 model will be inferenced with fp16 precision. \n" + "\t [QNN only] [backend_type]: QNN backend type. E.g., 'cpu', 'htp'. Mutually exclusive with 'backend_path'.\n" + "\t [QNN only] [backend_path]: QNN backend path. E.g., '/folderpath/libQnnHtp.so', '/winfolderpath/QnnHtp.dll'. Mutually exclusive with 'backend_type'.\n" + "\t [QNN only] [vtcm_mb]: QNN VTCM size in MB. default to 0(not set).\n" + "\t [QNN only] [htp_graph_finalization_optimization_mode]: QNN graph finalization optimization mode, options: '0', '1', '2', '3', default is '0'.\n" + "\t [QNN only] [soc_model]: The SoC Model number. Refer to QNN SDK documentation for specific values. Defaults to '0' (unknown). \n" + "\t [QNN only] [htp_arch]: The minimum HTP architecture. The driver will use ops compatible with this architecture. eg: '0', '68', '69', '73', '75'. Defaults to '0' (none). \n" + "\t [QNN only] [enable_htp_fp16_precision]: Enable the HTP_FP16 precision so that the float32 model will be inferenced with fp16 precision. \n" "\t Otherwise, it will be fp32 precision. Works for float32 model for HTP backend. Defaults to '1' (with FP16 precision.). \n" - "\t [enable_htp_weight_sharing]: Allows common weights across graphs to be shared and stored in a single context binary. Defaults to '1' (enabled).\n" - "\t [offload_graph_io_quantization]: Offload graph input quantization and graph output dequantization to another EP (typically CPU EP). \n" - "\t Defaults to '0' (QNN EP handles the graph I/O quantization and dequantization). \n" - "\t [enable_htp_spill_fill_buffer]: Enable HTP spill file buffer, used while generating QNN context binary." + "\t [QNN only] [offload_graph_io_quantization]: Offload graph input quantization and graph output dequantization to another EP (typically CPU EP). \n" + "\t Defaults to '1' (another EP (typically CPU EP) handles the graph I/O quantization and dequantization). \n" + "\t [QNN only] [enable_htp_spill_fill_buffer]: Enable HTP spill file buffer, used while generating QNN context binary.\n" "\t [Example] -i \"vtcm_mb|8 htp_arch|73\" \n" "\n" "\t-h: help\n"); @@ -109,8 +112,22 @@ static bool ParseSessionConfigs(const std::string& configs_string, /*static*/ bool CommandLineParser::ParseArguments(TestConfig& test_config, int argc, ORTCHAR_T* argv[]) { int ch; - while ((ch = getopt(argc, argv, ORT_TSTR("o:u:i:C:vh"))) != -1) { + while ((ch = getopt(argc, argv, ORT_TSTR("e:o:u:i:C:vh"))) != -1) { switch (ch) { + case 'e': + if (!CompareCString(optarg, ORT_TSTR("qnn"))) { + test_config.machine_config.provider_type_name = onnxruntime::kQnnExecutionProvider; + } else if (!CompareCString(optarg, ORT_TSTR("openvino"))) { + test_config.machine_config.provider_type_name = onnxruntime::kOpenVINOExecutionProvider; + } else if (!CompareCString(optarg, ORT_TSTR("tensorrt"))) { + test_config.machine_config.provider_type_name = onnxruntime::kTensorrtExecutionProvider; + } else if (!CompareCString(optarg, ORT_TSTR("vitisai"))) { + test_config.machine_config.provider_type_name = onnxruntime::kVitisAIExecutionProvider; + } else { + fprintf(stderr, "The execution provider is not included in this tool.\n"); + return false; + } + break; case 'v': test_config.run_config.f_verbose = true; break; @@ -135,7 +152,8 @@ static bool ParseSessionConfigs(const std::string& configs_string, std::string key(token.substr(0, pos)); std::string value(token.substr(pos + 1)); - if (key == "backend_path" || key == "vtcm_mb" || key == "soc_model" || key == "htp_arch") { + if (key == "backend_type" || key == "backend_path" || key == "vtcm_mb" || key == "soc_model" || + key == "htp_arch") { // no validation } else if (key == "htp_graph_finalization_optimization_mode") { std::unordered_set supported_htp_graph_final_opt_modes = {"0", "1", "2", "3"}; @@ -146,8 +164,8 @@ static bool ParseSessionConfigs(const std::string& configs_string, std::string str = str_stream.str(); ORT_THROW("Wrong value for htp_graph_finalization_optimization_mode. select from: " + str); } - } else if (key == "enable_htp_fp16_precision" || key == "enable_htp_weight_sharing" || - key == "offload_graph_io_quantization" || key == "enable_htp_spill_fill_buffer") { + } else if (key == "enable_htp_fp16_precision" || key == "offload_graph_io_quantization" || + key == "enable_htp_spill_fill_buffer") { std::unordered_set supported_options = {"0", "1"}; if (supported_options.find(value) == supported_options.end()) { std::ostringstream str_stream; @@ -157,12 +175,13 @@ static bool ParseSessionConfigs(const std::string& configs_string, ORT_THROW("Wrong value for " + key + ". select from: " + str); } } else { - ORT_THROW(R"(Wrong key type entered. Choose from options: ['backend_path', 'vtcm_mb', 'htp_performance_mode', - 'htp_graph_finalization_optimization_mode', 'soc_model', 'htp_arch', 'enable_htp_fp16_precision', 'enable_htp_weight_sharing', - 'offload_graph_io_quantization', 'enable_htp_spill_fill_buffer'])"); + ORT_THROW( + "Wrong key type entered. Choose from options: ['backend_type', 'backend_path', 'vtcm_mb', " + "'htp_performance_mode', 'htp_graph_finalization_optimization_mode', 'soc_model', 'htp_arch', " + "'enable_htp_fp16_precision', 'offload_graph_io_quantization', 'enable_htp_spill_fill_buffer']"); } - test_config.run_config.qnn_options[key] = value; + test_config.run_config.provider_options[key] = value; } break; } diff --git a/onnxruntime/test/qnn_ctx_gen/command_args_parser.h b/onnxruntime/test/ep_weight_sharing_ctx_gen/command_args_parser.h similarity index 100% rename from onnxruntime/test/qnn_ctx_gen/command_args_parser.h rename to onnxruntime/test/ep_weight_sharing_ctx_gen/command_args_parser.h diff --git a/onnxruntime/test/ep_weight_sharing_ctx_gen/main.cc b/onnxruntime/test/ep_weight_sharing_ctx_gen/main.cc new file mode 100644 index 0000000000000..18abe1eb131d8 --- /dev/null +++ b/onnxruntime/test/ep_weight_sharing_ctx_gen/main.cc @@ -0,0 +1,216 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "test_configuration.h" +#include "command_args_parser.h" + +// onnxruntime dependencies +#include "core/session/onnxruntime_cxx_api.h" +#include "core/session/onnxruntime_session_options_config_keys.h" + +// onnx dependencies +#include "onnx/onnx_pb.h" +#include + +using namespace onnxruntime; +using ProviderOptions = std::unordered_map; + +// from the last context cache Onnx model, find the EPContext node with main_context=1, +// get the max spill fill buffer size +static void GetEpContextInfoFromLastContextModel(const std::basic_string last_onnx_ctx_file, + int64_t& max_size) { + max_size = 0; + + onnx::ModelProto model; + std::ifstream onnx_file_stream(last_onnx_ctx_file, std::ios_base::binary); + model.ParseFromIstream(&onnx_file_stream); + + for (auto& node : model.graph().node()) { + if (node.op_type() == "EPContext") { + int64_t is_main_context = 0; + for (auto& attr : node.attribute()) { + if (attr.name() == "main_context") { + is_main_context = attr.i(); + } + if (attr.name() == "max_size") { + max_size = attr.i(); + } + } + if (is_main_context) { + return; + } + } + } + + onnx_file_stream.close(); +} + +// Update generated context cache Onnx model to have the same max_size (align with the last generated model) +static void UpdateEpContextModel(const std::vector>& ep_ctx_files, + int64_t max_size) { + for (auto ep_ctx_file : ep_ctx_files) { + onnx::ModelProto model; + std::ifstream onnx_file_stream(ep_ctx_file, std::ios_base::binary); + model.ParseFromIstream(&onnx_file_stream); + onnx_file_stream.close(); + + for (auto& node : *(model.mutable_graph()->mutable_node())) { + if (node.op_type() == "EPContext") { + int64_t is_main_context = 0; + int max_size_index = 0; + for (auto i = 0; i < node.attribute_size(); ++i) { + auto& attr = node.attribute()[i]; + if (attr.name() == "main_context") { + is_main_context = attr.i(); + } + if (attr.name() == "max_size") { + max_size = attr.i(); + max_size_index = i; + } + } + if (is_main_context) { + node.mutable_attribute(max_size_index)->set_i(max_size); + } + } + } + + // re-write the onnx ctx file + std::ofstream onnx_file_ostream(ep_ctx_file, std::ios_base::binary); + model.SerializeToOstream(&onnx_file_ostream); + onnx_file_ostream.close(); + } +} + +#ifdef _WIN32 +int real_main(int argc, wchar_t* argv[]) { +#else +int real_main(int argc, char* argv[]) { +#endif + qnnctxgen::TestConfig test_config; + if (!qnnctxgen::CommandLineParser::ParseArguments(test_config, argc, argv)) { + qnnctxgen::CommandLineParser::ShowUsage(); + return -1; + } + + OrtLoggingLevel logging_level = test_config.run_config.f_verbose + ? ORT_LOGGING_LEVEL_VERBOSE + : ORT_LOGGING_LEVEL_ERROR; + Ort::Env env(logging_level, "ep_weight_sharing"); + + ORT_TRY { + Ort::SessionOptions so; + so.SetLogId("ep_weight_sharing_ctx_gen_session_logger"); + // Set default session option to dump EPContext model with non-embed mode + so.AddConfigEntry(kOrtSessionOptionEpContextEnable, "1"); + so.AddConfigEntry(kOrtSessionOptionEpContextEmbedMode, "0"); + // enable ep.share_ep_contexts + so.AddConfigEntry(kOrtSessionOptionShareEpContexts, "1"); + + ProviderOptions provider_options; + + for (auto it : test_config.run_config.provider_options) { + provider_options[it.first] = it.second; + } + + for (auto it : test_config.run_config.session_config_entries) { + if (it.first == kOrtSessionOptionEpContextEnable && it.second != "1") { + std::cerr << "Need to enable ep context cache." << std::endl; + continue; + } + if (it.first == kOrtSessionOptionEpContextEmbedMode && it.second != "0") { + std::cerr << "Only support non-embed model for weight sharing." << std::endl; + continue; + } + if (it.first == kOrtSessionOptionEpContextFilePath) { + std::cout << "Not support to specify the generated Onnx context cache file name." << std::endl; + continue; + } + so.AddConfigEntry(it.first.c_str(), it.second.c_str()); + } + + for (auto model_path : test_config.model_file_paths) { + std::cout << "Model file path: " << ToUTF8String(model_path) << std::endl; + } + + // Generate context cache model files with QNN context binary files + // The context binary file generated later includes all graphs from previous models + { + std::string provider_name_ = test_config.machine_config.provider_type_name; + if (provider_name_ == onnxruntime::kQnnExecutionProvider) { +#ifdef USE_QNN + so.AppendExecutionProvider("QNN", provider_options); +#else + ORT_THROW("QNN is not supported in this build\n"); +#endif + } else if (!provider_name_.empty()) { + ORT_THROW("This execution provider is not included in this tool.\n"); + } + + size_t total_file_count = test_config.model_file_paths.size(); + for (size_t i = 0; i < total_file_count; ++i) { + auto model_path = test_config.model_file_paths[i]; + std::cout << "Generating context cache model for: " << ToUTF8String(model_path) << std::endl; + if (i == total_file_count - 1) { + so.AddConfigEntry(kOrtSessionOptionStopShareEpContexts, "1"); + } + Ort::Session session(env, model_path.c_str(), so); + } + } + + // Only with enable_htp_spill_fill_buffer enabled: + // Update generated context cache Onnx model to have the same max_size (align with the last generated model) + // so that the inference session can be created with any order of the ctx.onnx models + const std::string enable_htp_spill_fill_buffer = "enable_htp_spill_fill_buffer"; + auto pos = provider_options.find(enable_htp_spill_fill_buffer); + if (pos != provider_options.end() && pos->second == "1") { + std::cout << "Start to update the generated Onnx model to reflect the max_size." << std::endl; + + // The steps below only used for spill fill buffer enabled + std::vector> ep_ctx_files; + ep_ctx_files.reserve(test_config.model_file_paths.size()); + for (auto model_path : test_config.model_file_paths) { + auto dot_pos = model_path.find_last_of(ORT_TSTR(".")); + if (dot_pos != std::string::npos) { + model_path = model_path.substr(0, dot_pos) + ORT_TSTR("_ctx.onnx"); + } else { + model_path = model_path + ORT_TSTR("_ctx.onnx"); + } + ep_ctx_files.push_back(model_path); + } + + int64_t max_size = 0; + GetEpContextInfoFromLastContextModel(ep_ctx_files.back(), max_size); + ep_ctx_files.pop_back(); + + UpdateEpContextModel(ep_ctx_files, max_size); + } + } + ORT_CATCH(const Ort::Exception& e) { + std::cerr << "Failed to generate context cache file: " << e.what(); + return -1; + } + + std::cout << "Generation done!"; + return 0; +} + +#ifdef _WIN32 +int wmain(int argc, wchar_t* argv[]) { +#else +int main(int argc, char* argv[]) { +#endif + int retval = -1; + ORT_TRY { + retval = real_main(argc, argv); + } + ORT_CATCH(const std::exception& ex) { + ORT_HANDLE_EXCEPTION([&]() { + fprintf(stderr, "%s\n", ex.what()); + retval = -1; + }); + } + + ::google::protobuf::ShutdownProtobufLibrary(); + + return retval; +} diff --git a/onnxruntime/test/qnn_ctx_gen/test_configuration.h b/onnxruntime/test/ep_weight_sharing_ctx_gen/test_configuration.h similarity index 75% rename from onnxruntime/test/qnn_ctx_gen/test_configuration.h rename to onnxruntime/test/ep_weight_sharing_ctx_gen/test_configuration.h index bf4c7061a3484..198d03211f561 100644 --- a/onnxruntime/test/qnn_ctx_gen/test_configuration.h +++ b/onnxruntime/test/ep_weight_sharing_ctx_gen/test_configuration.h @@ -14,15 +14,20 @@ namespace onnxruntime { namespace qnnctxgen { +struct MachineConfig { + std::string provider_type_name{onnxruntime::kQnnExecutionProvider}; +}; + struct RunConfig { bool f_verbose{false}; std::unordered_map session_config_entries; - std::unordered_map qnn_options; + std::unordered_map provider_options; }; struct TestConfig { std::vector> model_file_paths; RunConfig run_config; + MachineConfig machine_config; }; } // namespace qnnctxgen diff --git a/onnxruntime/test/framework/inference_session_test.cc b/onnxruntime/test/framework/inference_session_test.cc index 1b06eb55afbd2..dc776f74d8758 100644 --- a/onnxruntime/test/framework/inference_session_test.cc +++ b/onnxruntime/test/framework/inference_session_test.cc @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -138,6 +139,7 @@ class FuseExecutionProvider : public IExecutionProvider { std::vector> GetCapability(const onnxruntime::GraphViewer& graph, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const override { // Fuse two add into one. std::vector> result; @@ -497,6 +499,30 @@ TEST(InferenceSessionTests, TestModelSerialization) { ASSERT_TRUE(session_object_emptyValidation.Initialize().IsOK()); } +TEST(InferenceSessionTests, RequestLoadCancellation) { + { + // Explicit cancel during load, small model is fine + SessionOptions so; + so.session_logid = "InferenceSessionTests.TestLoadCancellation"; + + const PathString model_uri = ORT_TSTR("testdata/constant_floats.onnx"); + InferenceSession session_object{so, GetEnvironment()}; + so.SetLoadCancellationFlag(true); + ASSERT_FALSE(session_object.Load(model_uri).IsOK()); + } + { + // Explicit cancel during initialize, small model is fine + const PathString model_uri = ORT_TSTR("testdata/constant_floats.onnx"); + SessionOptions so; + so.session_logid = "InferenceSessionTests.TestLoadCancellation"; + so.SetLoadCancellationFlag(false); + InferenceSession session_object{so, GetEnvironment()}; + ASSERT_STATUS_OK(session_object.Load(model_uri)); + so.SetLoadCancellationFlag(true); + ASSERT_FALSE(session_object.Initialize().IsOK()); + } +} + #ifdef ORT_RUN_EXTERNAL_ONNX_TESTS static bool Compare(const InputDefList& f_arg, const InputDefList& s_arg) { if (f_arg.size() != s_arg.size()) { diff --git a/onnxruntime/test/framework/session_state_test.cc b/onnxruntime/test/framework/session_state_test.cc index b6b915f90d99a..8f4eede76b905 100644 --- a/onnxruntime/test/framework/session_state_test.cc +++ b/onnxruntime/test/framework/session_state_test.cc @@ -27,6 +27,7 @@ #include "test/util/include/default_providers.h" #include "test/util/include/file_util.h" #include "core/optimizer/layout_transformation/layout_transformation.h" +#include "core/optimizer/graph_optimizer_registry.h" using namespace ONNX_NAMESPACE; namespace onnxruntime { @@ -264,7 +265,11 @@ TEST_P(SessionStateTestP, TestInitializerProcessing) { SessionState session_state(graph, execution_providers, tp.get(), nullptr, dtm, edlm, DefaultLoggingManager().DefaultLogger(), profiler, sess_options); - GraphPartitioner partitioner(krm, execution_providers); + // Create GraphOptimizerRegistry instance for providing predefined graph optimizers and selection functions for EPs to lookup + auto graph_optimizer_registry = std::make_unique(&sess_options, + execution_providers.Get(onnxruntime::kCpuExecutionProvider), + &DefaultLoggingManager().DefaultLogger()); + GraphPartitioner partitioner(krm, execution_providers, std::move(graph_optimizer_registry)); ASSERT_STATUS_OK( partitioner.Partition( graph, session_state.GetMutableFuncMgr(), @@ -350,8 +355,12 @@ TEST(SessionStateTest, TestInitializerMemoryAllocatedUsingNonArenaMemory) { SessionState session_state(graph, execution_providers, nullptr, nullptr, dtm, edlm, DefaultLoggingManager().DefaultLogger(), profiler, sess_options); + // Create GraphOptimizerRegistry instance for providing predefined graph optimizers and selection functions for EPs to lookup + auto graph_optimizer_registry = std::make_unique(&sess_options, + execution_providers.Get(onnxruntime::kCpuExecutionProvider), + &DefaultLoggingManager().DefaultLogger()); // Partition the graph - GraphPartitioner partitioner(krm, execution_providers); + GraphPartitioner partitioner(krm, execution_providers, std::move(graph_optimizer_registry)); ASSERT_STATUS_OK(partitioner.Partition( graph, session_state.GetMutableFuncMgr(), [&cpu_allocator](Graph& graph, bool& modified, const IExecutionProvider& execution_provider, @@ -409,8 +418,13 @@ TEST(SessionStateTest, TestInitializerMemoryAllocatedUsingNonArenaMemory) { SessionState session_state(graph, execution_providers, nullptr, nullptr, dtm, edlm, DefaultLoggingManager().DefaultLogger(), profiler, sess_options); + // Create GraphOptimizerRegistry instance for providing predefined graph optimizers and selection functions for EPs to lookup + auto graph_optimizer_registry = std::make_unique(&sess_options, + execution_providers.Get(onnxruntime::kCpuExecutionProvider), + &DefaultLoggingManager().DefaultLogger()); + // Partition the graph - GraphPartitioner partitioner(krm, execution_providers); + GraphPartitioner partitioner(krm, execution_providers, std::move(graph_optimizer_registry)); ASSERT_STATUS_OK(partitioner.Partition( graph, session_state.GetMutableFuncMgr(), [&cpu_allocator](Graph& graph, bool& modified, @@ -479,7 +493,12 @@ void LoadWithResourceAwarePartitioning(const ORTCHAR_T* model_path, SessionState session_state(model->MainGraph(), execution_providers, tp.get(), nullptr, dtm, edlm, default_logger, profiler, sess_options); - GraphPartitioner partitioner(krm, execution_providers); + // Create GraphOptimizerRegistry instance for providing predefined graph optimizers and selection functions for EPs to lookup + auto graph_optimizer_registry = std::make_unique(&sess_options, + execution_providers.Get(onnxruntime::kCpuExecutionProvider), + &DefaultLoggingManager().DefaultLogger()); + + GraphPartitioner partitioner(krm, execution_providers, std::move(graph_optimizer_registry)); layout_transformation::TransformLayoutFunction transform_layout_fn; layout_transformation::DebugGraphFn debug_graph_fn; ASSERT_STATUS_OK( diff --git a/onnxruntime/test/framework/type_info_test.cc b/onnxruntime/test/framework/type_info_test.cc index ee787fb071d97..d8ef668bf1c7e 100644 --- a/onnxruntime/test/framework/type_info_test.cc +++ b/onnxruntime/test/framework/type_info_test.cc @@ -22,9 +22,9 @@ TEST(TypeInfoTests, TensorProto) { auto tensor_type_info = OrtTypeInfo::FromTypeProto(tensor_type.value); ASSERT_EQ(ONNX_TYPE_TENSOR, tensor_type_info->type); - ASSERT_NE(nullptr, tensor_type_info->data); - ASSERT_EQ(ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, tensor_type_info->data->type); - ASSERT_TRUE(SpanEq(AsSpan({1, 2, 3, 4}), tensor_type_info->data->shape.GetDims())); + ASSERT_NE(nullptr, tensor_type_info->tensor_type_info); + ASSERT_EQ(ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, tensor_type_info->tensor_type_info->type); + ASSERT_TRUE(SpanEq(AsSpan({1, 2, 3, 4}), tensor_type_info->tensor_type_info->shape.GetDims())); } TEST(TypeInfoTests, SequenceWithTensorElement) { @@ -37,9 +37,9 @@ TEST(TypeInfoTests, SequenceWithTensorElement) { const auto& tensor_type_info = *seq_type_info->sequence_type_info->sequence_key_type_; ASSERT_EQ(ONNX_TYPE_TENSOR, tensor_type_info.type); - ASSERT_NE(nullptr, tensor_type_info.data); - ASSERT_EQ(ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, tensor_type_info.data->type); - ASSERT_TRUE(SpanEq(AsSpan({1, 2, 3, 4}), tensor_type_info.data->shape.GetDims())); + ASSERT_NE(nullptr, tensor_type_info.tensor_type_info); + ASSERT_EQ(ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, tensor_type_info.tensor_type_info->type); + ASSERT_TRUE(SpanEq(AsSpan({1, 2, 3, 4}), tensor_type_info.tensor_type_info->shape.GetDims())); } TEST(TypeInfoTests, OptionalWithTensorProto) { @@ -54,9 +54,9 @@ TEST(TypeInfoTests, OptionalWithTensorProto) { const auto& contained_type = *optional_type_info->optional_type_info->contained_type_; ASSERT_EQ(ONNX_TYPE_TENSOR, contained_type.type); - ASSERT_NE(nullptr, contained_type.data); - ASSERT_EQ(ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, contained_type.data->type); - ASSERT_TRUE(SpanEq(AsSpan({1, 2, 3, 4}), contained_type.data->shape.GetDims())); + ASSERT_NE(nullptr, contained_type.tensor_type_info); + ASSERT_EQ(ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, contained_type.tensor_type_info->type); + ASSERT_TRUE(SpanEq(AsSpan({1, 2, 3, 4}), contained_type.tensor_type_info->shape.GetDims())); } #if !defined(DISABLE_ML_OPS) @@ -74,11 +74,11 @@ TEST(TypeInfoTests, MapWithTensorValue) { const auto& tensor_type_info = *map_info.map_value_type_; ASSERT_EQ(ONNX_TYPE_TENSOR, tensor_type_info.type); - ASSERT_NE(nullptr, tensor_type_info.data); - ASSERT_EQ(ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, tensor_type_info.data->type); - ASSERT_TRUE(SpanEq(AsSpan({1, 2, 3, 4}), tensor_type_info.data->shape.GetDims())); + ASSERT_NE(nullptr, tensor_type_info.tensor_type_info); + ASSERT_EQ(ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, tensor_type_info.tensor_type_info->type); + ASSERT_TRUE(SpanEq(AsSpan({1, 2, 3, 4}), tensor_type_info.tensor_type_info->shape.GetDims())); } #endif } // namespace test -} // namespace onnxruntime \ No newline at end of file +} // namespace onnxruntime diff --git a/onnxruntime/test/mlas/bench/bench_qnbitgemm.cpp b/onnxruntime/test/mlas/bench/bench_qnbitgemm.cpp index 64d229889214b..88c036ac4854e 100644 --- a/onnxruntime/test/mlas/bench/bench_qnbitgemm.cpp +++ b/onnxruntime/test/mlas/bench/bench_qnbitgemm.cpp @@ -63,13 +63,13 @@ void RunQNBitGemmBenchmark(size_t BlkLen, tp.get()); std::unique_ptr Workspace; - if (const auto WorkspaceSize = MlasQNBitGemmBatchWorkspaceSize(M, N, K, 1, BlkBitWidth, BlkLen, ComputeType); + if (const auto WorkspaceSize = MlasQNBitGemmBatchWorkspaceSize(M, N, K, 1, BlkBitWidth, BlkLen, !Symmetric, ComputeType); WorkspaceSize > 0) { Workspace = std::make_unique(WorkspaceSize); } std::unique_ptr PackedQuantBData; - if (const auto PackedQuantBDataSize = MlasQNBitGemmPackQuantBDataSize(N, K, BlkBitWidth, BlkLen, ComputeType); + if (const auto PackedQuantBDataSize = MlasQNBitGemmPackQuantBDataSize(N, K, BlkBitWidth, BlkLen, !Symmetric, ComputeType); PackedQuantBDataSize > 0) { PackedQuantBData = std::make_unique(PackedQuantBDataSize); MlasQNBitGemmPackQuantBData(N, K, BlkBitWidth, BlkLen, ComputeType, QuantBData.data(), PackedQuantBData.get(), diff --git a/onnxruntime/test/mlas/bench/bench_rope.cpp b/onnxruntime/test/mlas/bench/bench_rope.cpp index 9103ba6424f65..b0630b9c8720b 100644 --- a/onnxruntime/test/mlas/bench/bench_rope.cpp +++ b/onnxruntime/test/mlas/bench/bench_rope.cpp @@ -4,42 +4,47 @@ #include "mlas.h" #include "benchmark/benchmark.h" #include "bench_util.h" +#include "core/framework/float16.h" -void RunRoPEBenchmark(size_t rotary_emb_dim, bool interleaved, benchmark::State& state) { - const float Pi = 2 * std::acos(0.0f); +using namespace onnxruntime; - std::vector input(rotary_emb_dim); +template +void RunRoPEBenchmark(size_t rotary_emb_dim, bool interleaved, benchmark::State& state) { + std::vector input(rotary_emb_dim); size_t table_len = interleaved ? rotary_emb_dim / 2 : rotary_emb_dim; - std::vector sin_data(table_len); - std::vector cos_data(table_len); - std::vector output_ref(rotary_emb_dim), output_impl(rotary_emb_dim); + std::vector sin_data(table_len); + std::vector cos_data(table_len); + std::vector output_ref(rotary_emb_dim), output_impl(rotary_emb_dim); for (size_t i = 0; i < rotary_emb_dim; ++i) { - input[i] = static_cast(i + 1); + input[i] = static_cast(i + 1.0f); } for (size_t i = 0; i < table_len; ++i) { - float theta = (float)i / 1000 * Pi; - sin_data[i] = std::sin(theta); - cos_data[i] = std::cos(theta); + // https://arxiv.org/pdf/2104.09864 section 3.4.3 + float theta_i = static_cast(pow(10000, -2.0f * i / rotary_emb_dim)); + sin_data[i] = static_cast(std::sin(theta_i)); + cos_data[i] = static_cast(std::cos(theta_i)); } // warm up run - MlasRotaryEmbedOneRow(&input[0], &sin_data[0], &cos_data[0], rotary_emb_dim, interleaved, &output_impl[0]); + MlasRotaryEmbedOneRow(&input[0], &sin_data[0], &cos_data[0], rotary_emb_dim, interleaved, &output_impl[0]); for (auto _ : state) { - MlasRotaryEmbedOneRow(&input[0], &sin_data[0], &cos_data[0], rotary_emb_dim, interleaved, &output_impl[0]); + MlasRotaryEmbedOneRow(&input[0], &sin_data[0], &cos_data[0], rotary_emb_dim, interleaved, &output_impl[0]); } } +template void RoPE(benchmark::State& state) { using onnxruntime::narrow; const auto rotary_emb_dim = narrow(state.range(0)); const auto interleaved = narrow(state.range(1)); - RunRoPEBenchmark(rotary_emb_dim, interleaved, state); + RunRoPEBenchmark(rotary_emb_dim, interleaved, state); } +template static void RoPEArgs(benchmark::internal::Benchmark* b) { b->ArgNames({"rotary_emb_dim", "interleaved"}); @@ -49,4 +54,5 @@ static void RoPEArgs(benchmark::internal::Benchmark* b) { }); } -BENCHMARK(RoPE)->Apply(RoPEArgs)->UseRealTime(); +BENCHMARK(RoPE)->Apply(RoPEArgs)->UseRealTime(); +BENCHMARK(RoPE)->Apply(RoPEArgs)->UseRealTime(); diff --git a/onnxruntime/test/mlas/unittest/test_eltwise.cpp b/onnxruntime/test/mlas/unittest/test_eltwise.cpp new file mode 100644 index 0000000000000..c4d4b9c0eb317 --- /dev/null +++ b/onnxruntime/test/mlas/unittest/test_eltwise.cpp @@ -0,0 +1,106 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "test_util.h" +#include "core/mlas/lib/mlasi.h" +#include "core/mlas/lib/eltwise.h" + +class MlasEltwiseAddTest : public MlasTestBase { + private: + MatrixGuardBuffer BufferInputLeft; + MatrixGuardBuffer BufferInputRight; + MatrixGuardBuffer BufferOutput; + MatrixGuardBuffer BufferOutputReference; + MatrixGuardBuffer BufferInputLeftFp16; + MatrixGuardBuffer BufferInputRightFp16; + MatrixGuardBuffer BufferOutputFp16; + + void Test(size_t N, float MinimumValue, float MaximumValue, const std::optional& ScalarValue = std::nullopt) { + float* InputLeft = BufferInputLeft.GetBuffer(N); + float* InputRight = BufferInputRight.GetBuffer(N); + float* Output = BufferOutput.GetBuffer(N); + float* OutputReference = BufferOutputReference.GetBuffer(N); + + std::default_random_engine generator(static_cast(N)); + std::uniform_real_distribution distribution(MinimumValue, MaximumValue); + + for (size_t n = 0; n < N; n++) { + InputLeft[n] = distribution(generator); + InputRight[n] = ScalarValue.value_or(distribution(generator)); + } + + for (size_t n = 0; n < N; n++) { + OutputReference[n] = InputLeft[n] + InputRight[n]; + } + + MlasEltwiseAdd(InputLeft, InputRight, Output, N); + + constexpr float AbsoluteTolerance = 1e-6f; + constexpr float RelativeTolerance = 1e-6f; + + for (size_t n = 0; n < N; n++) { + float diff = std::fabs(Output[n] - OutputReference[n]); + ASSERT_TRUE(diff <= AbsoluteTolerance || diff <= std::fabs(OutputReference[n]) * RelativeTolerance) + << " @" << n << " of " << N << ", got: " << Output[n] << ", expecting: " << OutputReference[n]; + } + } + +#if defined(MLAS_F16VEC_INTRINSICS_SUPPORTED) && defined(MLAS_TARGET_ARM64) + + void TestFp16(size_t N, float MinimumValue, float MaximumValue, const std::optional& ScalarValue = std::nullopt) { + MLAS_FP16* InputLeft = BufferInputLeftFp16.GetBuffer(N); + MLAS_FP16* InputRight = BufferInputRightFp16.GetBuffer(N); + MLAS_FP16* Output = BufferOutputFp16.GetBuffer(N); + + std::default_random_engine generator(static_cast(N)); + std::uniform_real_distribution distribution(MinimumValue, MaximumValue); + + for (size_t n = 0; n < N; n++) { + InputLeft[n] = MLAS_FP16(distribution(generator)); + InputRight[n] = MLAS_FP16(ScalarValue.value_or(distribution(generator))); + } + + MlasEltwiseAdd(InputLeft, InputRight, Output, N); + + constexpr float AbsoluteTolerance = 5e-4f; + constexpr float RelativeTolerance = 1e-3f; + + for (size_t n = 0; n < N; n++) { + float inLeft = InputLeft[n].ToFloat(); + float inRight = InputRight[n].ToFloat(); + float ref = inLeft + inRight; + float out = Output[n].ToFloat(); + float diff = std::fabs(out - ref); + ASSERT_TRUE(diff <= AbsoluteTolerance || diff <= std::fabs(ref) * RelativeTolerance) + << " @ " << inLeft << ", " << inRight << ", got: " << out << ", expecting: " << ref + << ", r-diff: " << diff / std::fabs(ref); + } + } + +#endif // defined(MLAS_F16VEC_INTRINSICS_SUPPORTED) && defined(MLAS_TARGET_ARM64) + + public: + static const char* GetTestSuiteName() { + static const std::string suite_name("Eltwise_Add"); + return suite_name.c_str(); + } + + void ExecuteShort(void) override { + for (size_t n = 1; n < 128; n++) { + Test(n, -10.f, 10.f); + Test(n, -10.f, 10.f, -5000.f); +#if defined(MLAS_F16VEC_INTRINSICS_SUPPORTED) && defined(MLAS_TARGET_ARM64) + TestFp16(n, -17.f, 11.f); + TestFp16(n, -17.f, 11.f, -5000.f); +#endif // defined(MLAS_F16VEC_INTRINSICS_SUPPORTED) && defined(MLAS_TARGET_ARM64) + } + } +}; + +static UNUSED_VARIABLE bool added_to_main = AddTestRegister([](bool is_short_execute) { + size_t count = 0; + if (is_short_execute) { + count += MlasDirectShortExecuteTests::RegisterShortExecute(); + } + return count; +}); diff --git a/onnxruntime/test/mlas/unittest/test_hgemm_neon.cpp b/onnxruntime/test/mlas/unittest/test_hgemm_neon.cpp index 6cb005d577fa3..d1622a14c8e33 100644 --- a/onnxruntime/test/mlas/unittest/test_hgemm_neon.cpp +++ b/onnxruntime/test/mlas/unittest/test_hgemm_neon.cpp @@ -388,7 +388,7 @@ class MlasNeonHGemmBTest : public MlasTestBase { public: MlasNeonHGemmBTest() - : seed_(rd_()), gen_(seed_), distrib_(-1.f, 1.f) { + : seed_(172387), gen_(seed_), distrib_(-1.f, 1.f) { } static const char* GetTestSuiteName() { diff --git a/onnxruntime/test/mlas/unittest/test_rope.cpp b/onnxruntime/test/mlas/unittest/test_rope.cpp index 54087a933fd9e..516bc866459a8 100644 --- a/onnxruntime/test/mlas/unittest/test_rope.cpp +++ b/onnxruntime/test/mlas/unittest/test_rope.cpp @@ -16,31 +16,34 @@ Module Name: #include "test_util.h" #include "mlas.h" +#include "core/framework/float16.h" #include "core/mlas/lib/rotary_embedding.h" -class MlasRoPETest : public MlasTestBase { - const float Pi = 2 * std::acos(0.0f); +using namespace onnxruntime; +template +class MlasRoPETest : public MlasTestBase { public: void Test(size_t rotary_emb_dim, bool interleaved) { - std::vector input(rotary_emb_dim); + std::vector input(rotary_emb_dim); size_t table_len = interleaved ? rotary_emb_dim / 2 : rotary_emb_dim; - std::vector sin_data(table_len); - std::vector cos_data(table_len); - std::vector output_ref(rotary_emb_dim), output_impl(rotary_emb_dim); + std::vector sin_data(table_len); + std::vector cos_data(table_len); + std::vector output_ref(rotary_emb_dim), output_impl(rotary_emb_dim); for (size_t i = 0; i < rotary_emb_dim; ++i) { - input[i] = static_cast(i + 1); + input[i] = static_cast(i + 1.0f); } for (size_t i = 0; i < table_len; ++i) { - float theta = (float)i / 1000 * Pi; - sin_data[i] = std::sin(theta); - cos_data[i] = std::cos(theta); + // https://arxiv.org/pdf/2104.09864 section 3.4.3 + float theta_i = static_cast(pow(10000, -2.0f * i / rotary_emb_dim)); + sin_data[i] = static_cast(std::sin(theta_i)); + cos_data[i] = static_cast(std::cos(theta_i)); } // Call the function - MlasRotaryEmbedOneRow_FallBack(&input[0], &sin_data[0], &cos_data[0], rotary_emb_dim, interleaved, &output_ref[0]); - MlasRotaryEmbedOneRow(&input[0], &sin_data[0], &cos_data[0], rotary_emb_dim, interleaved, &output_impl[0]); + MlasRotaryEmbedOneRow_FallBack(&input[0], &sin_data[0], &cos_data[0], rotary_emb_dim, interleaved, &output_ref[0]); + MlasRotaryEmbedOneRow(&input[0], &sin_data[0], &cos_data[0], rotary_emb_dim, interleaved, &output_impl[0]); for (size_t i = 0; i < rotary_emb_dim; i++) { ASSERT_TRUE(CloseEnough(output_impl[i], output_ref[i])) @@ -48,40 +51,49 @@ class MlasRoPETest : public MlasTestBase { << "rotary_emb_dim=" << rotary_emb_dim << ", interleaved=" << interleaved; } } - - public: }; // // Short Execute() test helper to register each test separately by all parameters. // -class RoPEShortExecuteTest : public MlasTestFixture { +template +class RoPEShortExecuteTest : public MlasTestFixture> { public: explicit RoPEShortExecuteTest(size_t rotary_emb_dim, bool interleaved) : rotary_emb_dim_(rotary_emb_dim), interleaved_(interleaved) {} void TestBody() override { - MlasTestFixture::mlas_tester->Test(rotary_emb_dim_, interleaved_); + MlasTestFixture>::mlas_tester->Test(rotary_emb_dim_, interleaved_); } static size_t RegisterSingleTest(size_t rotary_emb_dim, bool interleaved) { size_t tests_registered = 0; + std::string test_suite_name{"RoPE_"}; + if (std::is_same::value) { + test_suite_name += "fp32"; + } else if (std::is_same::value) { + test_suite_name += "fp16"; + } else { + ADD_FAILURE() << "Unknown type passed to test: " << test_suite_name; + return 0; // Return 0 since no test is registered + } + std::stringstream ss; ss << "/rotary_emb_dim" << rotary_emb_dim << "/interleaved" << interleaved; auto test_name = ss.str(); testing::RegisterTest( - "RoPE", + test_suite_name.c_str(), test_name.c_str(), nullptr, test_name.c_str(), __FILE__, __LINE__, // Important to use the fixture type as the return type here. - [=]() -> MlasTestFixture* { - return new RoPEShortExecuteTest(rotary_emb_dim, interleaved); + [=]() -> MlasTestFixture>* { + return new RoPEShortExecuteTest(rotary_emb_dim, interleaved); }); tests_registered += 1; @@ -116,7 +128,7 @@ class RoPEShortExecuteTest : public MlasTestFixture { // only test float RoPE with avx2 where RopeDispatch is assigned at this moment. #ifdef MLAS_TARGET_AMD64 static size_t RoPERegisterAllShortExecuteTests() { - return RoPEShortExecuteTest::RegisterShortExecuteTests(); + return RoPEShortExecuteTest::RegisterShortExecuteTests() + RoPEShortExecuteTest::RegisterShortExecuteTests(); } static UNUSED_VARIABLE bool added_to_main = AddTestRegister( diff --git a/onnxruntime/test/mlas/unittest/test_sqnbitgemm.cpp b/onnxruntime/test/mlas/unittest/test_sqnbitgemm.cpp index e22018ae2877f..16af51cfaa12d 100644 --- a/onnxruntime/test/mlas/unittest/test_sqnbitgemm.cpp +++ b/onnxruntime/test/mlas/unittest/test_sqnbitgemm.cpp @@ -265,13 +265,13 @@ class MlasSQNBitGemmTest : public MlasTestBase { } void* Workspace = nullptr; - if (const auto WorkspaceSize = MlasQNBitGemmBatchWorkspaceSize(M, N, K, 1, BlkBitWidth, BlkLen, ComputeType); + if (const auto WorkspaceSize = MlasQNBitGemmBatchWorkspaceSize(M, N, K, 1, BlkBitWidth, BlkLen, !Symmetric, ComputeType); WorkspaceSize > 0) { Workspace = BufferWorkspace.GetBuffer(WorkspaceSize); } void* PackedQuantBDataWorkspace = nullptr; - if (const auto PackedQuantBDataSize = MlasQNBitGemmPackQuantBDataSize(N, K, BlkBitWidth, BlkLen, ComputeType); + if (const auto PackedQuantBDataSize = MlasQNBitGemmPackQuantBDataSize(N, K, BlkBitWidth, BlkLen, !Symmetric, ComputeType); PackedQuantBDataSize > 0) { PackedQuantBDataWorkspace = BufferPackedQuantBData.GetBuffer(PackedQuantBDataSize); bool has_zp_input = QuantBZeroPoint != nullptr; diff --git a/onnxruntime/test/onnx/TestCase.cc b/onnxruntime/test/onnx/TestCase.cc index 3433a88515b53..024987ede0ce3 100644 --- a/onnxruntime/test/onnx/TestCase.cc +++ b/onnxruntime/test/onnx/TestCase.cc @@ -1410,6 +1410,8 @@ std::unique_ptr> GetBrokenTests(const std::string& provider broken_tests->insert({"convtranspose_1d", "Access violation 0xc000005 from call graphAddNode."}); broken_tests->insert({"convtranspose", "Access violation 0xc000005 from call graphAddNode."}); broken_tests->insert({"averagepool_2d_ceil", "result differs. expected 13.5 (41580000), got 0 (0)"}); + // Fails with QNN 2.32 + broken_tests->insert({"resize_upsample_scales_linear", "expected 1 (3f800000), got 0.25 (3e800000)"}); } #ifdef DISABLE_CONTRIB_OPS diff --git a/onnxruntime/test/onnx/main.cc b/onnxruntime/test/onnx/main.cc index 99c3e44e13013..1d66c488775d3 100644 --- a/onnxruntime/test/onnx/main.cc +++ b/onnxruntime/test/onnx/main.cc @@ -59,7 +59,8 @@ void usage() { "\t Refer to onnxruntime_session_options_config_keys.h for valid keys and values. \n" "\t [Example] -C \"session.disable_cpu_ep_fallback|1 ep.context_enable|1\" \n" "\t-i: Specify EP specific runtime options as key value pairs. Different runtime options available are: \n" - "\t [QNN only] [backend_path]: QNN backend path. e.g '/folderpath/libQnnHtp.so', '/folderpath/libQnnCpu.so'.\n" + "\t [QNN only] [backend_type]: QNN backend type. E.g., 'cpu', 'htp'. Mutually exclusive with 'backend_path'.\n" + "\t [QNN only] [backend_path]: QNN backend path. E.g., '/folderpath/libQnnHtp.so', '/winfolderpath/QnnHtp.dll'. Mutually exclusive with 'backend_type'.\n" "\t [QNN only] [profiling_level]: QNN profiling level, options: 'basic', 'detailed', default 'off'.\n" "\t [QNN only] [profiling_file_path]: QNN profiling file path if ETW not enabled.\n" "\t [QNN only] [rpc_control_latency]: QNN rpc control latency. default to 10.\n" @@ -80,7 +81,7 @@ void usage() { "\t [QNN only] [offload_graph_io_quantization]: Offload graph input quantization and graph output dequantization to another EP (typically CPU EP). \n" "\t Defaults to '0' (QNN EP handles the graph I/O quantization and dequantization). \n" "\t [Usage]: -e -i '| |' \n\n" - "\t [Example] [For QNN EP] -e qnn -i \"profiling_level|detailed backend_path|/folderpath/libQnnCpu.so\" \n\n" + "\t [Example] [For QNN EP] -e qnn -i \"profiling_level|detailed backend_type|cpu\" \n\n" "\t [SNPE only] [runtime]: SNPE runtime, options: 'CPU', 'GPU', 'GPU_FLOAT16', 'DSP', 'AIP_FIXED_TF'. \n" "\t [SNPE only] [priority]: execution priority, options: 'low', 'normal'. \n" "\t [SNPE only] [buffer_type]: options: 'TF8', 'TF16', 'UINT8', 'FLOAT', 'ITENSOR'. default: ITENSOR'. \n" @@ -554,7 +555,8 @@ int real_main(int argc, char* argv[], Ort::Env& env) { if (supported_profiling_level.find(value) == supported_profiling_level.end()) { ORT_THROW("Supported profiling_level: off, basic, detailed"); } - } else if (key == "rpc_control_latency" || key == "vtcm_mb" || key == "soc_model" || key == "device_id") { + } else if (key == "backend_type" || key == "rpc_control_latency" || key == "vtcm_mb" || key == "soc_model" || + key == "device_id") { // no validation } else if (key == "htp_performance_mode") { std::set supported_htp_perf_mode = {"burst", "balanced", "default", "high_performance", @@ -602,10 +604,11 @@ int real_main(int argc, char* argv[], Ort::Env& env) { ORT_THROW("Wrong value for ", key, ". select from: ", str); } } else { - ORT_THROW(R"(Wrong key type entered. Choose from options: ['backend_path', -'profiling_level', 'profiling_file_path', 'rpc_control_latency', 'vtcm_mb', 'htp_performance_mode', -'qnn_saver_path', 'htp_graph_finalization_optimization_mode', 'qnn_context_priority', -'soc_model', 'htp_arch', 'device_id', 'enable_htp_fp16_precision', 'offload_graph_io_quantization'])"); + ORT_THROW( + "Wrong key type entered. Choose from options: ['backend_type', 'backend_path', " + "'profiling_level', 'profiling_file_path', 'rpc_control_latency', 'vtcm_mb', 'htp_performance_mode', " + "'qnn_saver_path', 'htp_graph_finalization_optimization_mode', 'qnn_context_priority', " + "'soc_model', 'htp_arch', 'device_id', 'enable_htp_fp16_precision', 'offload_graph_io_quantization']"); } qnn_options[key] = value; diff --git a/onnxruntime/test/optimizer/graph_transform_test.cc b/onnxruntime/test/optimizer/graph_transform_test.cc index eeb5deb268c5a..a33b3148014f1 100755 --- a/onnxruntime/test/optimizer/graph_transform_test.cc +++ b/onnxruntime/test/optimizer/graph_transform_test.cc @@ -2204,6 +2204,10 @@ TEST_F(GraphTransformationTests, FuseCudaConvAddReluIdentity) { for (auto& node : p_model->MainGraph().Nodes()) { node.SetExecutionProviderType(kJsExecutionProvider); } +#elif defined(USE_WEBGPU) + for (auto& node : p_model->MainGraph().Nodes()) { + node.SetExecutionProviderType(kWebGpuExecutionProvider); + } #else for (auto& node : p_model->MainGraph().Nodes()) { node.SetExecutionProviderType(kCpuExecutionProvider); @@ -2232,6 +2236,10 @@ TEST_F(GraphTransformationTests, FuseCudaConvAdd) { for (auto& node : p_model->MainGraph().Nodes()) { node.SetExecutionProviderType(kJsExecutionProvider); } +#elif defined(USE_WEBGPU) + for (auto& node : p_model->MainGraph().Nodes()) { + node.SetExecutionProviderType(kWebGpuExecutionProvider); + } #else for (auto& node : p_model->MainGraph().Nodes()) { node.SetExecutionProviderType(kCpuExecutionProvider); @@ -2330,6 +2338,10 @@ TEST_F(GraphTransformationTests, FuseConvActivation) { for (auto& node : p_model->MainGraph().Nodes()) { node.SetExecutionProviderType(kJsExecutionProvider); } +#elif defined(USE_WEBGPU) + for (auto& node : p_model->MainGraph().Nodes()) { + node.SetExecutionProviderType(kWebGpuExecutionProvider); + } #else for (auto& node : p_model->MainGraph().Nodes()) { node.SetExecutionProviderType(kCpuExecutionProvider); @@ -2351,6 +2363,13 @@ TEST_F(GraphTransformationTests, FuseConvActivation) { } else { ASSERT_TRUE(op_to_count_after_fusion[model.second] == 0); } +#elif defined(USE_WEBGPU) + std::set webgpu_supported = {"Relu", "Clip", "Sigmoid", "Tanh", "LeakyRelu", "HardSigmoid"}; + if (webgpu_supported.find(model.second) == webgpu_supported.end()) { + ASSERT_EQ(op_to_count_before_fusion[model.second], op_to_count_after_fusion[model.second]); + } else { + ASSERT_TRUE(op_to_count_after_fusion[model.second] == 0); + } #else ASSERT_TRUE(op_to_count_after_fusion[model.second] == 0); #endif @@ -7700,6 +7719,18 @@ TEST_F(GraphTransformationTests, GatherSliceToSplitFusion_AllSlice_GraphInput) { 1, pre_graph_checker, post_graph_checker)); } +TEST_F(GraphTransformationTests, GatherSliceToSplitFusion_AllSlice_GraphInput_gh_issue_24203) { + // https://github.com/microsoft/onnxruntime/issues/24203 + // This bug is manifested when the model features nameless nodes and there are more than one + // SliceToSplitFusion resulting in multiple Split nodes with the same name. + const PathString CUSTOM_OP_MODEL_URI = ORT_TSTR("testdata/gh_issue_24203.onnx"); + SessionOptions session_options; + session_options.graph_optimization_level = TransformerLevel::Level2; + InferenceSession session(session_options, GetEnvironment()); + ASSERT_STATUS_OK(session.Load(CUSTOM_OP_MODEL_URI)); + ASSERT_STATUS_OK(session.Initialize()); +} + TEST_F(GraphTransformationTests, GatherSliceToSplitFusion_Combined) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* data_arg = builder.MakeInput({{144}}); diff --git a/onnxruntime/test/perftest/command_args_parser.cc b/onnxruntime/test/perftest/command_args_parser.cc index 5031d557ee2f0..591e277b2bbca 100644 --- a/onnxruntime/test/perftest/command_args_parser.cc +++ b/onnxruntime/test/perftest/command_args_parser.cc @@ -82,9 +82,10 @@ namespace perftest { "\t [OpenVINO only] [enable_opencl_throttling]: Enables OpenCL queue throttling for GPU device(Reduces the CPU Utilization while using GPU) \n" "\t [Example] [For OpenVINO EP] -e openvino -i \"device_type|CPU num_of_threads|5 enable_opencl_throttling|true cache_dir|\"\"\"\n" "\n" - "\t [QNN only] [backend_path]: QNN backend path. e.g '/folderpath/libQnnHtp.so', '/folderpath/libQnnCpu.so'.\n" + "\t [QNN only] [backend_type]: QNN backend type. E.g., 'cpu', 'htp'. Mutually exclusive with 'backend_path'.\n" + "\t [QNN only] [backend_path]: QNN backend path. E.g., '/folderpath/libQnnHtp.so', '/winfolderpath/QnnHtp.dll'. Mutually exclusive with 'backend_type'.\n" "\t [QNN only] [profiling_level]: QNN profiling level, options: 'basic', 'detailed', default 'off'.\n" - "\t [profiling_file_path] : QNN profiling file path if ETW not enabled.\n" + "\t [QNN only] [profiling_file_path] : QNN profiling file path if ETW not enabled.\n" "\t [QNN only] [rpc_control_latency]: QNN rpc control latency. default to 10.\n" "\t [QNN only] [vtcm_mb]: QNN VTCM size in MB. default to 0(not set).\n" "\t [QNN only] [htp_performance_mode]: QNN performance mode, options: 'burst', 'balanced', 'default', 'high_performance', \n" @@ -104,7 +105,7 @@ namespace perftest { "\t [QNN only] [enable_htp_spill_fill_buffer]: Enable HTP spill fill buffer, used while generating QNN context binary.\n" "\t [QNN only] [enable_htp_shared_memory_allocator]: Enable the QNN HTP shared memory allocator and use it for inputs and outputs. Requires libcdsprpc.so/dll to be available.\n" "\t Defaults to '0' (disabled).\n" - "\t [Example] [For QNN EP] -e qnn -i \"backend_path|/folderpath/libQnnCpu.so\" \n" + "\t [Example] [For QNN EP] -e qnn -i \"backend_type|cpu\" \n" "\n" "\t [TensorRT only] [trt_max_partition_iterations]: Maximum iterations for TensorRT parser to get capability.\n" "\t [TensorRT only] [trt_min_subgraph_size]: Minimum size of TensorRT subgraphs.\n" diff --git a/onnxruntime/test/perftest/ort_test_session.cc b/onnxruntime/test/perftest/ort_test_session.cc index 456ec6d75dbcb..2395ea7316b1b 100644 --- a/onnxruntime/test/perftest/ort_test_session.cc +++ b/onnxruntime/test/perftest/ort_test_session.cc @@ -199,11 +199,12 @@ OnnxRuntimeTestSession::OnnxRuntimeTestSession(Ort::Env& env, std::random_device std::string option_string = performance_test_config.run_config.ep_runtime_config_string; #endif ParseSessionConfigs(option_string, provider_options, - {"backend_path", "profiling_file_path", "profiling_level", "rpc_control_latency", - "vtcm_mb", "soc_model", "device_id", "htp_performance_mode", "qnn_saver_path", - "htp_graph_finalization_optimization_mode", "qnn_context_priority", "htp_arch", - "enable_htp_fp16_precision", "offload_graph_io_quantization", "enable_htp_spill_fill_buffer", - "enable_htp_shared_memory_allocator", "dump_json_qnn_graph", "json_qnn_graph_dir"}); + {"backend_type", "backend_path", "profiling_file_path", "profiling_level", + "rpc_control_latency", "vtcm_mb", "soc_model", "device_id", "htp_performance_mode", + "qnn_saver_path", "htp_graph_finalization_optimization_mode", "qnn_context_priority", + "htp_arch", "enable_htp_fp16_precision", "offload_graph_io_quantization", + "enable_htp_spill_fill_buffer", "enable_htp_shared_memory_allocator", "dump_json_qnn_graph", + "json_qnn_graph_dir"}); for (const auto& provider_option : provider_options) { const std::string& key = provider_option.first; const std::string& value = provider_option.second; @@ -216,7 +217,8 @@ OnnxRuntimeTestSession::OnnxRuntimeTestSession(Ort::Env& env, std::random_device if (supported_profiling_level.find(value) == supported_profiling_level.end()) { ORT_THROW("Supported profiling_level: off, basic, detailed"); } - } else if (key == "rpc_control_latency" || key == "vtcm_mb" || key == "soc_model" || key == "device_id") { + } else if (key == "backend_type" || key == "rpc_control_latency" || key == "vtcm_mb" || key == "soc_model" || + key == "device_id") { // no validation } else if (key == "htp_performance_mode") { std::set supported_htp_perf_mode = {"burst", "balanced", "default", "high_performance", @@ -419,12 +421,12 @@ select from 'TF8', 'TF16', 'UINT8', 'FLOAT', 'ITENSOR'. \n)"); "Select from 'gpu', or 'npu' \n"); } } else if (key == "performance_preference") { - std::set ov_supported_values = {"default", "high_performance", "minimal_power"}; + std::set ov_supported_values = {"default", "high_performance", "minimum_power"}; if (ov_supported_values.find(value) != ov_supported_values.end()) { } else { ORT_THROW( "[ERROR] [DML] You have selected a wrong configuration value for the key 'performance_preference'. " - "Select from 'default', 'high_performance' or 'minimal_power' \n"); + "Select from 'default', 'high_performance' or 'minimum_power' \n"); } } else if (key == "disable_metacommands") { std::set ov_supported_values = {"true", "True", "false", "False"}; diff --git a/onnxruntime/test/perftest/ort_test_session.h b/onnxruntime/test/perftest/ort_test_session.h index d6580812da8f0..71f797b0d5a35 100644 --- a/onnxruntime/test/perftest/ort_test_session.h +++ b/onnxruntime/test/perftest/ort_test_session.h @@ -37,9 +37,10 @@ class OnnxRuntimeTestSession : public TestSession { Ort::Session session_{nullptr}; std::mt19937 rand_engine_; std::uniform_int_distribution dist_; - std::vector> test_inputs_; OrtAllocator* allocator_ = Ort::AllocatorWithDefaultOptions(); + // Note: custom_allocator_, if used, must outlive the `Ort::Value`s allocated with it in test_inputs_ and outputs_. Ort::Allocator custom_allocator_{nullptr}; + std::vector> test_inputs_; std::vector outputs_; std::vector output_names_; // The same size with output_names_. diff --git a/onnxruntime/test/providers/base_tester.cc b/onnxruntime/test/providers/base_tester.cc index 6bfe7bc3856ba..85f96206b5dba 100644 --- a/onnxruntime/test/providers/base_tester.cc +++ b/onnxruntime/test/providers/base_tester.cc @@ -174,7 +174,7 @@ static std::unique_ptr MakeSparseTensor(MLDataType data_type, cons return p_tensor; } -void BaseTester::CopyDataToTensor(gsl::span data, Tensor& dst) { +void BaseTester::CopyDataToTensor(gsl::span data, Tensor& dst) { ORT_ENFORCE(dst.SizeInBytes() >= data.size_bytes(), "Not enough space in the destination tensor"); memcpy(dst.MutableDataRaw(), data.data(), data.size_bytes()); } @@ -203,7 +203,7 @@ void BaseTester::AddSparseCooTensorData(std::vector& data, MLDataType data_type, const char* name, gsl::span dims, - gsl::span values, + gsl::span values, gsl::span indices, const ValidateOutputParams& check_params, const std::vector* dim_params) { @@ -247,7 +247,7 @@ void BaseTester::AddSparseCsrTensorData(std::vector& data, MLDataType data_type, const char* name, gsl::span dims, - gsl::span values, + gsl::span values, gsl::span inner_indices, gsl::span outer_indices, const ValidateOutputParams& check_params, @@ -537,7 +537,7 @@ void BaseTester::Run(ExpectResult expect_result, const std::string& expected_fai SessionOptions so; so.use_per_session_threads = false; so.session_logid = test_name_; - so.session_log_verbosity_level = 1; + so.session_log_verbosity_level = 0; so.execution_mode = execution_mode; so.use_deterministic_compute = use_determinism_; so.graph_optimization_level = TransformerLevel::Default; // 'Default' == off diff --git a/onnxruntime/test/providers/base_tester.h b/onnxruntime/test/providers/base_tester.h index 512b3402c5986..d39cc3c750dec 100644 --- a/onnxruntime/test/providers/base_tester.h +++ b/onnxruntime/test/providers/base_tester.h @@ -868,7 +868,7 @@ class BaseTester { void AddShapeToTensorData(NodeArg& node_arg, gsl::span dims, const std::vector* dim_params); - void CopyDataToTensor(gsl::span data, Tensor& dst); + void CopyDataToTensor(gsl::span data, Tensor& dst); #if !defined(DISABLE_SPARSE_TENSORS) NodeArg MakeSparseNodeArg(int32_t dtype, const char* name, @@ -879,7 +879,7 @@ class BaseTester { MLDataType data_type, const char* name, gsl::span dims, - gsl::span values, + gsl::span values, gsl::span indices, const ValidateOutputParams& check_params, const std::vector* dim_params = nullptr); @@ -895,7 +895,7 @@ class BaseTester { MLDataType data_type, const char* name, gsl::span dims, - gsl::span values, + gsl::span values, gsl::span inner_indices, gsl::span outer_indices, const ValidateOutputParams& check_params, diff --git a/onnxruntime/test/providers/coreml/coreml_basic_test.cc b/onnxruntime/test/providers/coreml/coreml_basic_test.cc index a9aa78b7a3229..3505193b77683 100644 --- a/onnxruntime/test/providers/coreml/coreml_basic_test.cc +++ b/onnxruntime/test/providers/coreml/coreml_basic_test.cc @@ -246,7 +246,7 @@ TEST(CoreMLExecutionProviderTest, TestOrtFormatModel) { #endif } -#if defined(COREML_ENABLE_MLPROGRAM) +#if defined(USE_COREML) // Names in CoreML cannot start with [0-9] or contain anything but "[a-z][A-Z][0-9]_" // Test that we fix invalid names in model inputs, initializers and outputs. // This is only enforced for ML Program, so we only do name sanitization when creating an ML Program format model. diff --git a/onnxruntime/test/providers/cpu/activation/activation_op_test.cc b/onnxruntime/test/providers/cpu/activation/activation_op_test.cc index 724118d7419d2..9201da348e75c 100644 --- a/onnxruntime/test/providers/cpu/activation/activation_op_test.cc +++ b/onnxruntime/test/providers/cpu/activation/activation_op_test.cc @@ -125,7 +125,7 @@ TEST_F(ActivationOpTest, Relu) { {}, {}, /*is_tensorrt_supported=*/false, /*opset_version= */ 14); -#if defined(MLAS_F16VEC_INTRINSICS_SUPPORTED) || defined(COREML_ENABLE_MLPROGRAM) +#if defined(MLAS_F16VEC_INTRINSICS_SUPPORTED) || defined(USE_COREML) TestActivationOp( "Relu", input_values_fp16, @@ -139,7 +139,7 @@ TEST_F(ActivationOpTest, Relu) { #endif // MLAS_F16VEC_INTRINSICS_SUPPORTED } -#if defined(USE_CUDA) || defined(USE_ROCM) || defined(COREML_ENABLE_MLPROGRAM) +#if defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_COREML) TEST_F(ActivationOpTest, Sigmoid_fp16) { #ifdef USE_CUDA int min_cuda_architecture = 530; @@ -413,7 +413,7 @@ TEST_F(ActivationOpTest, LeakyRelu) { {{"alpha", alpha}}, {}); } -#if defined(MLAS_F16VEC_INTRINSICS_SUPPORTED) || defined(COREML_ENABLE_MLPROGRAM) +#if defined(MLAS_F16VEC_INTRINSICS_SUPPORTED) || defined(USE_COREML) TEST_F(ActivationOpTest, LeakyRelu_fp16) { OpTester test("LeakyRelu", 11); float alpha = 0.01f; // oneDNN set alpha equal to 0.01 diff --git a/onnxruntime/test/providers/cpu/activation/activation_op_test.h b/onnxruntime/test/providers/cpu/activation/activation_op_test.h index 59813f433dc41..04d116e29d3b0 100644 --- a/onnxruntime/test/providers/cpu/activation/activation_op_test.h +++ b/onnxruntime/test/providers/cpu/activation/activation_op_test.h @@ -105,7 +105,7 @@ class ActivationOpTest : public ::testing::Test { std::random_device rd; std::mt19937 gen(rd()); std::uniform_real_distribution dist(low, high); -#ifdef COREML_ENABLE_MLPROGRAM +#ifdef USE_COREML // please check onnxruntime/onnxruntime/core/providers/coreml/builders/helper.cc:81 std::vector batch_size_list = {1, 2, 4, 9, 100}; #else diff --git a/onnxruntime/test/providers/cpu/controlflow/loop_test.cc b/onnxruntime/test/providers/cpu/controlflow/loop_test.cc index 9c0b779870c70..a5fd37361a255 100644 --- a/onnxruntime/test/providers/cpu/controlflow/loop_test.cc +++ b/onnxruntime/test/providers/cpu/controlflow/loop_test.cc @@ -576,11 +576,10 @@ TEST(Loop, InfiniteLoopTermination) { test.Run(OpTester::ExpectResult::kExpectFailure, "Exiting due to terminate flag being set to true", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}, &session_run_options); // Disable TensorRT on unsupported data type BOOL - // call get to propagate any exception - terminator_result.get(); - // done with the thread terminator_thread.join(); + // call get to propagate any exception + terminator_result.get(); } // Add basic test to trigger types override logic in Graph::InferAndVerifySubgraphTypes as well as diff --git a/onnxruntime/test/providers/cpu/math/element_wise_ops_test.cc b/onnxruntime/test/providers/cpu/math/element_wise_ops_test.cc index d87ee861752c7..fbd9d10a56c77 100644 --- a/onnxruntime/test/providers/cpu/math/element_wise_ops_test.cc +++ b/onnxruntime/test/providers/cpu/math/element_wise_ops_test.cc @@ -32,7 +32,7 @@ void TestBinaryFloat16(const char* op_name, bool enable_bf16 = true) { { std::vector> execution_providers; -#ifdef COREML_ENABLE_MLPROGRAM +#ifdef USE_COREML execution_providers.push_back(DefaultCoreMLExecutionProvider(true)); #elif USE_CUDA execution_providers.push_back(DefaultCudaExecutionProvider()); @@ -76,7 +76,7 @@ void TestUnaryFloat16(const char* op_name, bool run_bf16 = true) { { std::vector> execution_providers; -#ifdef COREML_ENABLE_MLPROGRAM +#ifdef USE_COREML execution_providers.push_back(DefaultCoreMLExecutionProvider(true)); #elif USE_CUDA execution_providers.push_back(DefaultCudaExecutionProvider()); @@ -968,8 +968,15 @@ TEST(MathOpTest, Abs) { test.Run(); } -#ifdef USE_DNNL +#if defined(USE_CUDA) || defined(USE_DNNL) TEST(MathOpTest, Abs_bfloat16) { +#ifdef USE_CUDA + int min_cuda_architecture = 530; + if (!HasCudaEnvironment(min_cuda_architecture)) { + LOGS_DEFAULT(WARNING) << "Hardware does NOT support BF16"; + return; + } +#endif #ifdef USE_DNNL if (!DnnlHasBF16Support()) { LOGS_DEFAULT(WARNING) << "Hardware does NOT support BF16"; @@ -980,9 +987,19 @@ TEST(MathOpTest, Abs_bfloat16) { std::vector dims{2, 2}; test_bf16.AddInput("X", dims, MakeBFloat16({1.0f, -2.0f, -0.0f, -10.0f})); test_bf16.AddOutput("Y", dims, MakeBFloat16({1.0f, 2.0f, 0.0f, 10.0f})); - test_bf16.Run(); + + std::vector> execution_providers; +#if defined(USE_CUDA) + execution_providers.push_back(DefaultCudaExecutionProvider()); +#endif + +#if defined(USE_DNNL) + execution_providers.push_back(DefaultDnnlExecutionProvider()); +#endif + + test_bf16.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &execution_providers); } -#endif // USE_DNNL +#endif // USE_CUDA || USE_DNNL TEST(MathOpTest, Abs_int8) { OpTester test("Abs"); @@ -1409,7 +1426,7 @@ TEST(MathOpTest, Pow_float16_float16) { dims, {1.0f, 256.0f, 2.0f, 1.0f}, false); } -#if defined(USE_CUDA) || defined(USE_ROCM) || defined(COREML_ENABLE_MLPROGRAM) +#if defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_COREML) TEST(MathOpTest, Pow_float_float16) { OpTester test("Pow", 12); std::vector dims{4}; @@ -1423,7 +1440,7 @@ TEST(MathOpTest, Pow_float_float16) { execution_providers.push_back(DefaultCudaExecutionProvider()); #elif USE_ROCM execution_providers.push_back(DefaultRocmExecutionProvider()); -#elif COREML_ENABLE_MLPROGRAM +#elif USE_COREML execution_providers.push_back(DefaultCoreMLExecutionProvider(true)); #endif test.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &execution_providers); diff --git a/onnxruntime/test/providers/cpu/math/matmul_test.cc b/onnxruntime/test/providers/cpu/math/matmul_test.cc index 298e870f348fc..504e645738344 100644 --- a/onnxruntime/test/providers/cpu/math/matmul_test.cc +++ b/onnxruntime/test/providers/cpu/math/matmul_test.cc @@ -158,6 +158,112 @@ std::vector> GenerateTestCases() { // clang-format on })}); +#ifdef USE_WEBGPU + test_cases.push_back( + {"test 3D tensors with M = 1", + {6, 1, 8}, + {1, 8, 3}, + {6, 1, 3}, + real_expected_vals({ + // clang-format off + 420, 448, 476, + 1092, 1184, 1276, + 1764, 1920, 2076, + 2436, 2656, 2876, + 3108, 3392, 3676, + 3780, 4128, 4476, + // clang-format on + })}); + + test_cases.push_back( + {"test 4D tensors with M = 1", + {2, 3, 1, 8}, + {1, 1, 8, 3}, + {2, 3, 1, 3}, + real_expected_vals({420, 448, 476, 1092, 1184, 1276, 1764, 1920, 2076, 2436, 2656, 2876, 3108, 3392, 3676, 3780, 4128, 4476})}); + + test_cases.push_back( + {"test 4D tensors", + {2, 3, 4, 3}, + {2, 3, 3, 5}, + {2, 3, 4, 5}, + real_expected_vals({ + // clang-format off + 25, 28, 31, 34, 37, 70, 82, 94, 106, 118, 115, 136, 157, 178, 199, 160, 190, 220, + 250, 280, 790, 829, 868, 907, 946, 970, 1018, 1066, 1114, 1162, 1150, 1207, 1264, + 1321, 1378, 1330, 1396, 1462, 1528, 1594, 2635, 2710, 2785, 2860, 2935, 2950, 3034, + 3118, 3202, 3286, 3265, 3358, 3451, 3544, 3637, 3580, 3682, 3784, 3886, 3988, 5560, + 5671, 5782, 5893, 6004, 6010, 6130, 6250, 6370, 6490, 6460, 6589, 6718, 6847, 6976, + 6910, 7048, 7186, 7324, 7462, 9565, 9712, 9859, 10006, 10153, 10150, 10306, 10462, + 10618, 10774, 10735, 10900, 11065, 11230, 11395, 11320, 11494, 11668, 11842, 12016, + 14650, 14833, 15016, 15199, 15382, 15370, 15562, 15754, 15946, 16138, 16090, 16291, + 16492, 16693, 16894, 16810, 17020, 17230, 17440, 17650 + // clang-format on + })}); + + // Test case: multiplies 2D broadcasted to 4D tensors + test_cases.push_back( + {"test 2D broadcasted to 4D tensors", + {2, 4}, + {4, 3, 2, 4, 2}, + {4, 3, 2, 2, 2}, + real_expected_vals({ + // clang-format off + 28, 34, 76, 98, 76, 82, 252, 274, 124, 130, 428, 450, 172, 178, 604, 626, + 220, 226, 780, 802, 268, 274, 956, 978, 316, 322, 1132, 1154, 364, 370, + 1308, 1330, 412, 418, 1484, 1506, 460, 466, 1660, 1682, 508, 514, 1836, + 1858, 556, 562, 2012, 2034, 604, 610, 2188, 2210, 652, 658, 2364, 2386, + 700, 706, 2540, 2562, 748, 754, 2716, 2738, 796, 802, 2892, 2914, 844, + 850, 3068, 3090, 892, 898, 3244, 3266, 940, 946, 3420, 3442, 988, 994, + 3596, 3618, 1036, 1042, 3772, 3794, 1084, 1090, 3948, 3970, 1132, 1138, + 4124, 4146 + // clang-format on + })}); + + // Test case: multiplies 4D broadcasted to 5D tensors + test_cases.push_back( + {"test 4D broadcasted to 5D tensors", + {3, 1, 2, 4}, + {4, 3, 2, 4, 2}, + {4, 3, 2, 2, 2}, + real_expected_vals({ + // clang-format off + 28, 34, 76, 98, 76, 82, 252, 274, 732, 770, 1036, 1090, 1036, 1074, 1468, + 1522, 2460, 2530, 3020, 3106, 3020, 3090, 3708, 3794, 316, 322, 1132, + 1154, 364, 370, 1308, 1330, 2556, 2594, 3628, 3682, 2860, 2898, 4060, + 4114, 5820, 5890, 7148, 7234, 6380, 6450, 7836, 7922, 604, 610, 2188, + 2210, 652, 658, 2364, 2386, 4380, 4418, 6220, 6274, 4684, 4722, 6652, + 6706, 9180, 9250, 11276, 11362, 9740, 9810, 11964, 12050, 892, 898, 3244, + 3266, 940, 946, 3420, 3442, 6204, 6242, 8812, 8866, 6508, 6546, 9244, + 9298, 12540, 12610, 15404, 15490, 13100, 13170, 16092, 16178 + + // clang-format on + })}); + + // Test case: same ranks different broadcast small 1 + test_cases.push_back( + {"test same ranks different broadcast small 1", + {2, 1, 2, 2}, + {1, 2, 2, 1}, + {2, 2, 2, 1}, + real_expected_vals({1, 3, 3, 13, 5, 7, 23, 33})}); + + // Test case: same ranks different broadcast larger 0 + test_cases.push_back( + {"test same ranks different broadcast larger 0", + {1, 2, 2, 8}, + {2, 1, 8, 1}, + {2, 2, 2, 1}, + real_expected_vals({140, 364, 588, 812, 364, 1100, 1836, 2572})}); + + // Test case: same ranks different broadcast larger 1 + test_cases.push_back( + {"test same ranks different broadcast larger 1", + {2, 1, 2, 8}, + {1, 2, 8, 1}, + {2, 2, 2, 1}, + real_expected_vals({140, 364, 364, 1100, 588, 812, 1836, 2572})}); +#endif return test_cases; } @@ -189,6 +295,17 @@ void RunMatMulTest(int32_t opset_version, bool is_a_constant, bool is_b_constant excluded_providers.insert(kNnapiExecutionProvider); } + // TODO:: Change MatMulNaive Shader to support these test cases webgpu + std::unordered_set webgpu_excluded_test_cases{ + "test left 1D", + "test right 1D", + "test 2D empty input"}; + + // if test in webgpu_excluded_test_cases, add webgpu to excluded_providers + if (webgpu_excluded_test_cases.find(t.name) != webgpu_excluded_test_cases.end()) { + excluded_providers.insert(kWebGpuExecutionProvider); + } + test.ConfigExcludeEps(excluded_providers) .Config(run_with_tunable_op) .RunWithConfig(); @@ -210,7 +327,7 @@ TEST(MathOpTest, MatMulFloatType) { RunMatMulTest(7, false, true); } -#if defined(USE_CUDA) || defined(USE_ROCM) || defined(COREML_ENABLE_MLPROGRAM) || defined(USE_XNNPACK) +#if defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_COREML) || defined(USE_XNNPACK) TEST(MathOpTest, MatMulFloat16) { #ifdef USE_CUDA int min_cuda_architecture = 530; @@ -234,10 +351,18 @@ TEST(MathOpTest, MatMulDoubleType) { } TEST(MathOpTest, MatMulInt32Type) { + // Webgpu does not support int32 matmul + if (DefaultWebGpuExecutionProvider().get() != nullptr) { + GTEST_SKIP() << "Skipping because of the following error: Webgpu does not support int32 matmul"; + } RunMatMulTest(9); } TEST(MathOpTest, MatMulUint32Type) { + // Webgpu does not support uint32 matmul + if (DefaultWebGpuExecutionProvider().get() != nullptr) { + GTEST_SKIP() << "Skipping because of the following error: Webgpu does not support uint32 matmul"; + } RunMatMulTest(9); } @@ -263,20 +388,26 @@ void RunMatMulZeroKTest() { // No special case is implemented. test.ConfigExcludeEps({kCoreMLExecutionProvider, kNnapiExecutionProvider, kDmlExecutionProvider, kDnnlExecutionProvider, kQnnExecutionProvider, - kOpenVINOExecutionProvider}) + kOpenVINOExecutionProvider, kWebGpuExecutionProvider}) .Config(run_with_tunable_op) .RunWithConfig(); } TEST(MathOpTest, MatMulZeroKFloatType) { + if (DefaultWebGpuExecutionProvider().get() != nullptr) { + GTEST_SKIP() << "Skipping because of the following error: Webgpu does not support zero-sized tensor"; + } RunMatMulZeroKTest(); } TEST(MathOpTest, MatMulZeroKInt32Type) { + if (DefaultWebGpuExecutionProvider().get() != nullptr) { + GTEST_SKIP() << "Skipping because of the following error: Webgpu does not support zero-sized tensor"; + } RunMatMulZeroKTest(); } -#if defined(USE_CUDA) || defined(USE_ROCM) || defined(COREML_ENABLE_MLPROGRAM) || defined(USE_XNNPACK) +#if defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_COREML) || defined(USE_XNNPACK) TEST(MathOpTest, MatMul_Float16) { #ifdef USE_CUDA int min_cuda_architecture = 530; diff --git a/onnxruntime/test/providers/cpu/math/sign_test.cc b/onnxruntime/test/providers/cpu/math/sign_test.cc index a01c2b26ea8b5..0da6a2ed55f2c 100644 --- a/onnxruntime/test/providers/cpu/math/sign_test.cc +++ b/onnxruntime/test/providers/cpu/math/sign_test.cc @@ -207,7 +207,7 @@ TEST(MathOpTest, Sign_MLFloat16) { // test.Run(OpTester::ExpectResult::kExpectSuccess); //} -#if defined(USE_DNNL) +#if defined(USE_CUDA) || defined(USE_DNNL) TEST(MathOpTest, Sign_bfloat16) { #ifdef USE_DNNL if (!DnnlHasBF16Support()) { @@ -228,9 +228,15 @@ TEST(MathOpTest, Sign_bfloat16) { TestImpl(input.cbegin(), input.cend(), std::back_inserter(output)); test.AddOutput("output", input_dims, output); std::vector> execution_providers; + +#if defined(USE_CUDA) + execution_providers.push_back(DefaultCudaExecutionProvider()); +#endif + #if defined(USE_DNNL) execution_providers.push_back(DefaultDnnlExecutionProvider()); -#endif // USE_DNNL +#endif + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &execution_providers); } #endif diff --git a/onnxruntime/test/providers/cpu/math/softmax_test.cc b/onnxruntime/test/providers/cpu/math/softmax_test.cc index 6f7930f722564..1c6375ebdb0b1 100644 --- a/onnxruntime/test/providers/cpu/math/softmax_test.cc +++ b/onnxruntime/test/providers/cpu/math/softmax_test.cc @@ -170,11 +170,11 @@ TEST(SoftmaxOperator, ThreeAndFourDimsAxis0) { RunTest(input_vals_60, expected_vals, three_dimensions, /*opset*/ 7, /*axis*/ 0, // axis=0 is not supported by TensorRT - {kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kDnnlExecutionProvider}); + {kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kDnnlExecutionProvider, kWebGpuExecutionProvider}); RunTest(input_vals_60, expected_vals, four_dimensions, /*opset*/ 7, /*axis*/ 0, // axis=0 is not supported by TensorRT - {kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kDnnlExecutionProvider}); + {kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kDnnlExecutionProvider, kWebGpuExecutionProvider}); } TEST(SoftmaxOperator, ThreeAndFourDimsSecondLastAxis) { @@ -201,10 +201,10 @@ TEST(SoftmaxOperator, ThreeAndFourDimsSecondLastAxis) { 0.040478885f, 0.033857856f, 0.080346674f, 0.06199841f, 0.040481992f}; RunTest(input_vals_60, expected_vals, three_dimensions, /*opset*/ 7, /*axis*/ 1, - {kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kDnnlExecutionProvider}); + {kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kDnnlExecutionProvider, kWebGpuExecutionProvider}); RunTest(input_vals_60, expected_vals, four_dimensions, /*opset*/ 7, /*axis*/ 2, - {kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kDnnlExecutionProvider}); + {kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kDnnlExecutionProvider, kWebGpuExecutionProvider}); } TEST(SoftmaxOperator, ThreeAndFourDimsSecondLastAxis_opset13) { @@ -376,8 +376,9 @@ TEST(SoftmaxOperator, DimWithZero) { RunTest(x_vals, expected_vals, dimensions, /*opset*/ -1, /*axis*/ 0, {kTensorrtExecutionProvider, - kNnapiExecutionProvider, // NNAPI softmax does not support empty input - kQnnExecutionProvider} // QNN doesn't support dim 0 + kNnapiExecutionProvider, // NNAPI softmax does not support empty input + kWebGpuExecutionProvider, // WebGPU does not support dim 0 + kQnnExecutionProvider} // QNN doesn't support dim 0 ); } diff --git a/onnxruntime/test/providers/cpu/model_tests.cc b/onnxruntime/test/providers/cpu/model_tests.cc index e3c86a137484f..d5f6f1ddf700e 100644 --- a/onnxruntime/test/providers/cpu/model_tests.cc +++ b/onnxruntime/test/providers/cpu/model_tests.cc @@ -444,8 +444,8 @@ ::std::vector<::std::basic_string> GetParameterStrings() { // The other EPs can choose which opsets to test. // If an EP doesn't have any CI build pipeline, then there is no need to specify any opset. #ifdef USE_TENSORRT - // tensorrt: only enable opset 12 to 17 of onnx tests - provider_names[provider_name_tensorrt] = {opset12, opset14, opset15, opset16, opset17}; + // tensorrt: only enable opset 14 to 17 of onnx tests + provider_names[provider_name_tensorrt] = {opset14, opset15, opset16, opset17}; #endif #ifdef USE_MIGRAPHX provider_names[provider_name_migraphx] = {opset7, opset8, opset9, opset10, opset11, opset12, opset13, opset14, opset15, opset16, opset17, opset18}; @@ -619,6 +619,7 @@ ::std::vector<::std::basic_string> GetParameterStrings() { ORT_TSTR("resnet101v2"), ORT_TSTR("resnet101v2"), ORT_TSTR("vgg19"), + ORT_TSTR("dequantizelinear"), ORT_TSTR("tf_inception_resnet_v2"), ORT_TSTR("tf_inception_v1"), ORT_TSTR("tf_inception_v3"), diff --git a/onnxruntime/test/providers/cpu/nn/batch_norm_op_test.cc b/onnxruntime/test/providers/cpu/nn/batch_norm_op_test.cc index f8ebca5ff9a1b..a529d572d7cca 100644 --- a/onnxruntime/test/providers/cpu/nn/batch_norm_op_test.cc +++ b/onnxruntime/test/providers/cpu/nn/batch_norm_op_test.cc @@ -704,7 +704,7 @@ TEST(BatchNormTest, NonSpatial_Complicated) { } // Only CUDA and ROCm kernels have float 16 support -#if defined(USE_CUDA) || defined(USE_ROCM) || defined(COREML_ENABLE_MLPROGRAM) +#if defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_COREML) TEST(BatchNormTest, BatchNorm2d_fp16) { vector X{-0.91221f, -0.283559f, 0.937637f, 2.09818f, -0.100199f, -0.608113f, 0.444562f, -1.07505f, 0.940591f, -0.922262f, 0.0931303f, 0.69611f, 1.55187f, 0.159808f, 0.914874f, -1.24856f, -1.98928f, -0.331621f, diff --git a/onnxruntime/test/providers/cpu/nn/conv_fp16_test.cc b/onnxruntime/test/providers/cpu/nn/conv_fp16_test.cc index 4253e36e02548..1404071928e09 100644 --- a/onnxruntime/test/providers/cpu/nn/conv_fp16_test.cc +++ b/onnxruntime/test/providers/cpu/nn/conv_fp16_test.cc @@ -3,7 +3,7 @@ #include "core/mlas/inc/mlas.h" -#if defined(MLAS_F16VEC_INTRINSICS_SUPPORTED) || defined(COREML_ENABLE_MLPROGRAM) || defined(USE_XNNPACK) +#if defined(MLAS_F16VEC_INTRINSICS_SUPPORTED) || defined(USE_COREML) || defined(USE_XNNPACK) #include "gtest/gtest.h" #include "test/providers/provider_test_utils.h" @@ -30,7 +30,7 @@ struct ConvOpAndTestAttributes { /* Please notice that, we have predefined macros in the head of the file -#if defined(MLAS_F16VEC_INTRINSICS_SUPPORTED) || defined(COREML_ENABLE_MLPROGRAM) +#if defined(MLAS_F16VEC_INTRINSICS_SUPPORTED) || defined(USE_COREML) When we have these two macro defines, this UT will turn into green light and work. If attributes.activation is set the NhwcFusedConv contrib op is used. @@ -518,7 +518,7 @@ TEST(ConvFp16Test, Conv3D_1) { vector{1, 1, 1}, // kernel_shape vector{0, 0, 0, 0, 0, 0}, // pads vector{1, 1, 1}, // strides - {} // excluded EPs + {kWebGpuExecutionProvider} // excluded EPs }; vector X = { @@ -557,7 +557,7 @@ TEST(ConvFp16Test, Conv3D_2) { vector{1, 1, 1}, // kernel_shape vector{2, 2, 2, 2, 2, 2}, // pads vector{2, 2, 2}, // strides - {} // excluded EPs + {kWebGpuExecutionProvider} // excluded EPs }; vector X = { @@ -601,7 +601,7 @@ TEST(ConvFp16Test, Conv3D_Bias) { vector{2, 2, 2}, // kernel_shape vector{2, 2, 2, 2, 2, 2}, // pads vector{2, 2, 2}, // strides - {} // excluded EPs + {kWebGpuExecutionProvider} // excluded EPs }; vector X = { @@ -1082,7 +1082,7 @@ TEST(ConvFp16Test, Pointwise_3D) { vector{1, 1, 1}, // kernel_shape vector{0, 0, 0, 0, 0, 0}, // pads vector{1, 1, 1}, // strides - {} // excluded EPs + {kWebGpuExecutionProvider} // excluded EPs }; vector X = { diff --git a/onnxruntime/test/providers/cpu/nn/conv_integer_test.cc b/onnxruntime/test/providers/cpu/nn/conv_integer_test.cc index a5378fa3cefd7..c98d9e28b2f46 100644 --- a/onnxruntime/test/providers/cpu/nn/conv_integer_test.cc +++ b/onnxruntime/test/providers/cpu/nn/conv_integer_test.cc @@ -254,5 +254,45 @@ TEST(ConvIntegerTest, WithStride3_2D_u8u8) { test.Run(); } +TEST(ConvIntegerTest, NoXZeroPoint) { + OpTester test("ConvInteger", 10); + std::vector x_dims{1, 1, 3, 3}; + test.AddInput("x", x_dims, + {2, 3, 4, + 5, 6, 7, + 8, 9, 10}); + std::vector w_dims{1, 1, 2, 2}; + test.AddInput("w", w_dims, + {2, 2, + 2, 2}); + test.AddOptionalInputEdge(); + test.AddInput("w_zero_point", {}, {1}); + std::vector y_dims{1, 1, 2, 2}; + test.AddOutput("y", y_dims, + {16, 20, + 28, 32}); + test.Run(); +} + +// provide optional input with empty name for w. tests that input args == 4 but the w_zero_point does not exist. +TEST(ConvIntegerTest, NoWZeroPoint) { + OpTester test("ConvInteger", 10); + std::vector x_dims{1, 1, 3, 3}; + test.AddInput("x", x_dims, + {2, 3, 4, + 5, 6, 7, + 8, 9, 10}); + std::vector w_dims{1, 1, 2, 2}; + test.AddInput("w", w_dims, + {2, 2, + 2, 2}); + test.AddInput("x_zero_point", {}, {1}); + test.AddOptionalInputEdge(); + std::vector y_dims{1, 1, 2, 2}; + test.AddOutput("y", y_dims, + {24, 32, + 48, 56}); + test.Run(); +} } // namespace test } // namespace onnxruntime diff --git a/onnxruntime/test/providers/cpu/nn/conv_op_test.cc b/onnxruntime/test/providers/cpu/nn/conv_op_test.cc index a3a3dd939cbf0..06434d5b59ec6 100644 --- a/onnxruntime/test/providers/cpu/nn/conv_op_test.cc +++ b/onnxruntime/test/providers/cpu/nn/conv_op_test.cc @@ -489,7 +489,7 @@ TEST(ConvTest, Conv3D_1) { vector{1, 1, 1}, // kernel_shape vector{0, 0, 0, 0, 0, 0}, // pads vector{1, 1, 1}, // strides - {} // excluded EPs + {kWebGpuExecutionProvider} // excluded EPs }; vector X = {-0.43337246775627136f, -0.48385289311408997f, -0.30954962968826294f, @@ -526,7 +526,7 @@ TEST(ConvTest, Conv3D_2) { vector{1, 1, 1}, // kernel_shape vector{2, 2, 2, 2, 2, 2}, // pads vector{2, 2, 2}, // strides - {} // excluded EPs + {kWebGpuExecutionProvider} // excluded EPs }; vector X = {0.010772407054901123f, -0.43806642293930054f, 0.455391526222229f, -0.28657248616218567f, @@ -569,7 +569,7 @@ TEST(ConvTest, Conv3D_Bias) { vector{2, 2, 2}, // kernel_shape vector{2, 2, 2, 2, 2, 2}, // pads vector{2, 2, 2}, // strides - {} // excluded EPs + {kWebGpuExecutionProvider} // excluded EPs }; vector X = {0.46796226501464844f, -0.4613912105560303f, 0.33512794971466064f, -0.4010460674762726f, @@ -916,7 +916,7 @@ TEST(ConvTest, ConvDimWithZero) { vector{1, 1}, // kernel_shape vector{0, 0, 0, 0}, // pads vector{1, 1}, // strides - {} // excluded EPs + {kWebGpuExecutionProvider} // excluded EPs }; vector X = vector(); diff --git a/onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc b/onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc index 83b27f10fe04f..198fa07ae4ed0 100644 --- a/onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc +++ b/onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc @@ -933,7 +933,7 @@ TEST(ConvTransposeTest, DimWithZero) { TestConvTransposeOp(attrs, {X, W}, {X_shape, W_shape}, expected_vals, Y_shape, OpTester::ExpectResult::kExpectSuccess, "", {kCudaNHWCExecutionProvider, kTensorrtExecutionProvider, - kAclExecutionProvider, kQnnExecutionProvider}); + kAclExecutionProvider, kQnnExecutionProvider, kWebGpuExecutionProvider}); } TEST(ConvTransposeTest, ConvTranspose_3D) { @@ -1068,7 +1068,7 @@ TEST(ConvTransposeTest, ConvTranspose_3D) { TestConvTransposeOp(attrs, {X, W, B}, {X_shape, W_shape, B_shape}, expected_vals, Y_shape, OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kCudaExecutionProvider, - kCudaNHWCExecutionProvider, kQnnExecutionProvider}); + kCudaNHWCExecutionProvider, kQnnExecutionProvider, kWebGpuExecutionProvider}); } TEST(ConvTransposeTest, ConvTranspose_1D_AsymmetricPads) { diff --git a/onnxruntime/test/providers/cpu/nn/group_norm_op_test.cc b/onnxruntime/test/providers/cpu/nn/group_norm_op_test.cc index ac517193a2c77..3d8d188867023 100644 --- a/onnxruntime/test/providers/cpu/nn/group_norm_op_test.cc +++ b/onnxruntime/test/providers/cpu/nn/group_norm_op_test.cc @@ -6,7 +6,7 @@ #include "test/common/tensor_op_test_utils.h" #include "test/util/include/default_providers.h" -#ifdef COREML_ENABLE_MLPROGRAM +#ifdef USE_COREML using namespace std; namespace onnxruntime { namespace test { diff --git a/onnxruntime/test/providers/cpu/nn/instance_norm_op_test.cc b/onnxruntime/test/providers/cpu/nn/instance_norm_op_test.cc index 341bb8a4fc957..46b74f2c2eb9d 100644 --- a/onnxruntime/test/providers/cpu/nn/instance_norm_op_test.cc +++ b/onnxruntime/test/providers/cpu/nn/instance_norm_op_test.cc @@ -121,7 +121,7 @@ TEST(InstanceNormalizationOpTest, InstanceNormBatch2) { } // Only CUDA and ROCm kernels have float 16 support -#if defined(USE_CUDA) || defined(USE_ROCM) || defined(COREML_ENABLE_MLPROGRAM) +#if defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_COREML) TEST(InstanceNormalizationOpTest, InstanceNormBatch1_fp16) { OpTester test("InstanceNormalization"); diff --git a/onnxruntime/test/providers/cpu/nn/pool_fp16_op_test.cc b/onnxruntime/test/providers/cpu/nn/pool_fp16_op_test.cc index d4e0af5011525..24cdb818b9e32 100644 --- a/onnxruntime/test/providers/cpu/nn/pool_fp16_op_test.cc +++ b/onnxruntime/test/providers/cpu/nn/pool_fp16_op_test.cc @@ -3,7 +3,7 @@ #include "core/mlas/inc/mlas.h" -#if defined(MLAS_F16VEC_INTRINSICS_SUPPORTED) || defined(COREML_ENABLE_MLPROGRAM) || defined(USE_XNNPACK) +#if defined(MLAS_F16VEC_INTRINSICS_SUPPORTED) || defined(USE_COREML) || defined(USE_XNNPACK) || defined(USE_WEBGPU) #include "core/providers/cpu/nn/pool.h" #include "gtest/gtest.h" @@ -280,7 +280,10 @@ TEST(PoolFp16Test, MaxPool_Dilation_Ceil1_2d) { test.AddInput("X", x_dims, x_vals); test.AddOutput("Y", expected_dims, expected_vals); - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kAclExecutionProvider}); + + // TODO: Enable the case for WebGPU once ceil is supported. + test.Run(OpTester::ExpectResult::kExpectSuccess, "", + {kTensorrtExecutionProvider, kAclExecutionProvider, kWebGpuExecutionProvider}); } TEST(PoolTest, MaxPool_DilationPadding_3d) { @@ -484,7 +487,10 @@ TEST(PoolFp16Test, AveragePool_10_ceil1_2d) { test.AddInput("X", x_dims, x_vals); test.AddOutput("Y", expected_dims, expected_vals); - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kAclExecutionProvider}); + + // TODO: Enable the case for WebGPU once ceil is supported. + test.Run(OpTester::ExpectResult::kExpectSuccess, "", + {kTensorrtExecutionProvider, kAclExecutionProvider, kWebGpuExecutionProvider}); } TEST(PoolFp16Test, GlobalAveragePool) { diff --git a/onnxruntime/test/providers/cpu/nn/pool_op_test.cc b/onnxruntime/test/providers/cpu/nn/pool_op_test.cc index 24a8c8491b632..36150d03a7d36 100644 --- a/onnxruntime/test/providers/cpu/nn/pool_op_test.cc +++ b/onnxruntime/test/providers/cpu/nn/pool_op_test.cc @@ -70,7 +70,7 @@ TEST(PoolTest, MaxPool) { // Only CUDA kernel has float 16 support // Disable for now, still investigating the issue with cudnn lib -#if defined(USE_CUDA) || defined(COREML_ENABLE_MLPROGRAM) +#if defined(USE_CUDA) || defined(USE_COREML) TEST(PoolTest, MaxPool_F16) { #if defined(USE_CUDA) int min_cuda_architecture = 530; @@ -178,9 +178,10 @@ static void MaxPool_8_WithIndexTest(bool has_index, int64_t storage_order = 0) { storage_order == 0 ? test.AddOutput("Indices", expected_dims, expected_indices_row) : test.AddOutput("Indices", expected_dims, expected_indices_col); } + // TODO: Enable the case for WebGPU once WGSL can support int64. test.Run(OpTester::ExpectResult::kExpectSuccess, "", - {kDnnlExecutionProvider, kTensorrtExecutionProvider, - kAclExecutionProvider, kArmNNExecutionProvider, kOpenVINOExecutionProvider}); + {kDnnlExecutionProvider, kTensorrtExecutionProvider, kAclExecutionProvider, kArmNNExecutionProvider, + kOpenVINOExecutionProvider, kWebGpuExecutionProvider}); } TEST(PoolTest, MaxPool_8_With_Index) { @@ -268,8 +269,10 @@ static void MaxPool1D_8_WithIndexTest(int64_t storage_order) { test.AddInput("X", x_dims, x_vals); test.AddOutput("Y", expected_dims, expected_vals); test.AddOutput("Indices", expected_dims, expected_indices); + + // TODO: Enable the case for WebGPU once WGSL can support int64. test.Run(OpTester::ExpectResult::kExpectSuccess, "", - {kTensorrtExecutionProvider, kAclExecutionProvider}); + {kTensorrtExecutionProvider, kAclExecutionProvider, kWebGpuExecutionProvider}); } TEST(PoolTest, MaxPool1D_8_With_Index) { @@ -641,6 +644,7 @@ TEST(PoolTest, MaxPool_10_Dilation_Ceil1_2d) { test.AddInput("X", x_dims, x_vals); test.AddOutput("Y", expected_dims, expected_vals); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kAclExecutionProvider}); } @@ -1000,6 +1004,7 @@ TEST(PoolTest, AveragePool_10_ceil1_2d) { test.AddInput("X", x_dims, x_vals); test.AddOutput("Y", expected_dims, expected_vals); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kAclExecutionProvider}); } @@ -1817,8 +1822,10 @@ TEST(PoolTest, MaxPoolDimWithZeroForN) { test.AddInput("X", x_dims, x_vals); test.AddOutput("Y", expected_dims, expected_vals); + + // TODO: Fix WebGPU Transpose error: "Invalid dispatch group size (0, 1, 1)". test.Run(OpTester::ExpectResult::kExpectSuccess, "", - {kTensorrtExecutionProvider, kQnnExecutionProvider}); + {kTensorrtExecutionProvider, kQnnExecutionProvider, kWebGpuExecutionProvider}); } } // namespace test diff --git a/onnxruntime/test/providers/cpu/reduction/reduction_ops_test.cc b/onnxruntime/test/providers/cpu/reduction/reduction_ops_test.cc index 61a16d41e3e59..92cd82c2c9420 100644 --- a/onnxruntime/test/providers/cpu/reduction/reduction_ops_test.cc +++ b/onnxruntime/test/providers/cpu/reduction/reduction_ops_test.cc @@ -1375,7 +1375,7 @@ TEST(ReductionOpTest, ReduceMax_double) { test.Run(); } -#if defined(USE_CUDA) || defined(USE_ROCM) || defined(COREML_ENABLE_MLPROGRAM) +#if defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_COREML) TEST(ReductionOpTest, ReduceMax_half) { OpTester test("ReduceMax"); test.AddAttribute("axes", std::vector{1, 2}); @@ -2158,7 +2158,7 @@ TEST(ReductionOpTest, ReduceMin_double) { test.Run(); } -#if defined(USE_CUDA) || defined(USE_ROCM) || defined(COREML_ENABLE_MLPROGRAM) +#if defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_COREML) TEST(ReductionOpTest, ReduceMin_half) { OpTester test("ReduceMin"); test.AddAttribute("axes", std::vector{0, 2}); @@ -2356,7 +2356,7 @@ TEST(ReductionOpTest, ReduceSum_int32) { test.Run(); } -#if defined(USE_CUDA) || defined(USE_ROCM) || defined(COREML_ENABLE_MLPROGRAM) +#if defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_COREML) TEST(ReductionOpTest, ReduceSumHalfHalf) { OpTester test("ReduceSum"); test.AddAttribute("keepdims", (int64_t)0); @@ -6044,6 +6044,7 @@ void test_empty_set(const std::string& op, int opset, bool axes_as_input, float kQnnExecutionProvider, kRocmExecutionProvider, kTensorrtExecutionProvider, + kWebGpuExecutionProvider, }); } diff --git a/onnxruntime/test/providers/cpu/tensor/quantize_linear_test.cc b/onnxruntime/test/providers/cpu/tensor/quantize_linear_test.cc index 51aae0cfd4adf..4e7a6356a5129 100644 --- a/onnxruntime/test/providers/cpu/tensor/quantize_linear_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/quantize_linear_test.cc @@ -156,7 +156,8 @@ TEST(DequantizeLinearOpTest, Scalar) { test.AddInput("x_zero_point", {}, {-10}); test.AddOutput("y", {}, {220.0f}); // Disable Tensorrt EP due to error:node1_quantize_scale_node: out of bounds channel axis 1. Number of input dimensions is 0. - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); + // Disable WebGPU EP due to error: needs at least component size 4 + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kWebGpuExecutionProvider}); } // dequantize with scalar data @@ -167,7 +168,8 @@ TEST(DequantizeLinearOpMLFloat16Test, Scalar) { test.AddInput("x_zero_point", {}, {-10}); test.AddOutput("y", {}, {MLFloat16(220.0f)}); // Disable Tensorrt EP due to error:node1_quantize_scale_node: out of bounds channel axis 1. Number of input dimensions is 0. - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); + // Disable WebGPU EP due to error: needs at least component size 4 + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kWebGpuExecutionProvider}); } // dequantize without zero point @@ -176,6 +178,45 @@ TEST(DequantizeLinearOpTest, Without_Zero_Point) { test.AddInput("x", {}, {100}); test.AddInput("x_scale", {}, {2.0f}); test.AddOutput("y", {}, {200.0f}); + // No DQ allowed without corresponding Q. Skip since TRT10 + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kWebGpuExecutionProvider}); +} + +// dequantize without zero point int8 (testing 8 elements for webgpu) +TEST(DequantizeLinearOpTest, No_Zero_Point_int8) { + OpTester test("DequantizeLinear", 10); + test.AddInput("x", {1, 8}, {-10, 50, 100, 120, -9, 49, 99, 119}); + test.AddInput("x_scale", {}, {2.0f}); + test.AddOutput("y", {1, 8}, {-20.0f, 100.0f, 200.0f, 240.0f, -18.0f, 98.0f, 198.0f, 238.0f}); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // No DQ allowed without corresponding Q. Skip since TRT10 +} + +// dequantize without zero point uint8 (testing 8 elements for webgpu) +TEST(DequantizeLinearOpTest, No_Zero_Point_uint8) { + OpTester test("DequantizeLinear", 10); + test.AddInput("x", {1, 8}, {10, 50, 100, 180, 9, 49, 99, 179}); + test.AddInput("x_scale", {}, {2.0f}); + test.AddOutput("y", {1, 8}, {20.0f, 100.0f, 200.0f, 360.0f, 18.0f, 98.0f, 198.0f, 358.0f}); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // No DQ allowed without corresponding Q. Skip since TRT10 +} + +// dequantize zero point int8 (testing 8 elements for webgpu) +TEST(DequantizeLinearOpTest, Zero_Point_int8) { + OpTester test("DequantizeLinear", 10); + test.AddInput("x", {1, 8}, {-10, 50, 100, 120, -9, 49, 99, 119}); + test.AddInput("x_scale", {}, {2.0f}); + test.AddInput("zero_point", {}, {-10}); + test.AddOutput("y", {1, 8}, {0.0f, 120.0f, 220.0f, 260.0f, 2.0f, 118.0f, 218.0f, 258.0f}); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // No DQ allowed without corresponding Q. Skip since TRT10 +} + +// dequantize zero point uint8 (testing 8 elements for webgpu) +TEST(DequantizeLinearOpTest, Zero_Point_uint8) { + OpTester test("DequantizeLinear", 10); + test.AddInput("x", {1, 8}, {10, 50, 100, 180, 9, 49, 99, 119}); + test.AddInput("x_scale", {}, {2.0f}); + test.AddInput("zero_point", {}, {10}); + test.AddOutput("y", {1, 8}, {0.0f, 80.0f, 180.0f, 340.0f, -2.0f, 78.0f, 178.0f, 218.0f}); test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // No DQ allowed without corresponding Q. Skip since TRT10 } diff --git a/onnxruntime/test/providers/cpu/tensor/resize_op_test.cc b/onnxruntime/test/providers/cpu/tensor/resize_op_test.cc index 84fb6157b8884..f0d3a53f0ac81 100644 --- a/onnxruntime/test/providers/cpu/tensor/resize_op_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/resize_op_test.cc @@ -107,11 +107,11 @@ TEST(ResizeOpTest, NhwcResizeOpLinearDownSampleTest_tf_crop_and_resize_with_extr 10.0f, 10.0f, 10.0f}; test.AddOutput("Y", {N, static_cast(H * scales[1]), static_cast(W * scales[2]), C}, Y); - // CUDA: result mismatch due to not implementing NHWC support + // CUDA | WEBGPU: result mismatch due to not implementing NHWC support // TensorRT: results mismatch // ROCm: results mismatch test.Run(OpTester::ExpectResult::kExpectSuccess, "", - {kCudaExecutionProvider, kCudaNHWCExecutionProvider, kTensorrtExecutionProvider, kRocmExecutionProvider}); + {kCudaExecutionProvider, kCudaNHWCExecutionProvider, kTensorrtExecutionProvider, kRocmExecutionProvider, kWebGpuExecutionProvider}); } TEST(ResizeOpTest, NhwcResizeOpLinearDownSampleTest_tf_crop_and_resize_with_extrapolation_uint8) { @@ -282,10 +282,10 @@ TEST(ResizeOpTest, NhwcResizeOpLinearDownSampleTest_4DBilinear) { std::vector Y = {2.66666651f, 4.3333331f}; test.AddOutput("Y", {N, static_cast(H * scales[1]), static_cast(W * scales[2]), C}, Y); - // CUDA: result mismatch due to not implementing NHWC support + // CUDA | WEBGPU: result mismatch due to not implementing NHWC support // ROCm: results mismatch // TRT: Segmentation fault in A100 - std::unordered_set excluded_providers({kCudaExecutionProvider, kCudaNHWCExecutionProvider, kRocmExecutionProvider}); + std::unordered_set excluded_providers({kCudaExecutionProvider, kCudaNHWCExecutionProvider, kRocmExecutionProvider, kWebGpuExecutionProvider}); test.Run(OpTester::ExpectResult::kExpectSuccess, "", ExcludeTrtOnA100(excluded_providers)); } @@ -2034,6 +2034,8 @@ void TestAntialiasing(std::map attributes, excluded_eps.insert(kTensorrtExecutionProvider); // Test is flaky on kCudaNHWCExecutionProvider excluded_eps.insert(kCudaNHWCExecutionProvider); + // Not implementing Antialias support on kWebGpuExecutionProvider + excluded_eps.insert(kWebGpuExecutionProvider); test.Run(OpTester::ExpectResult::kExpectSuccess, "", excluded_eps); } @@ -2473,7 +2475,7 @@ TEST(ResizeOpTest, Antialias_Large_half_pixel) { // DML implementation is equivalent to resize with variable input window size while ORT using a convolution approach. // Absolute error is for ORT CPU. test.AddOutput("Y", output_shape, Y, false, /*rel_error*/ 0.0f, /*abs_error*/ 0.12f); - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kQnnExecutionProvider}); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kQnnExecutionProvider, kWebGpuExecutionProvider}); } // Test without anti-aliasing for better comparison with DirectML diff --git a/onnxruntime/test/providers/cpu/tensor/space_depth_ops_test.cc b/onnxruntime/test/providers/cpu/tensor/space_depth_ops_test.cc index d0620a794e4d5..a40b85b7754a3 100644 --- a/onnxruntime/test/providers/cpu/tensor/space_depth_ops_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/space_depth_ops_test.cc @@ -44,9 +44,7 @@ TEST(TensorOpTest, SpaceToDepthTest_1) { 3.1f, 3.3f}; test.AddOutput("output", {N, C * blocksize * blocksize, H / blocksize, W / blocksize}, result); - // TODO: Test is flaky on QNN EP (CPU backend). - // Re-enable when the QnnCPUBackendTests.DISABLED_SpaceToDepth_Flaky test is fixed. - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kQnnExecutionProvider}); + test.Run(OpTester::ExpectResult::kExpectSuccess); } TEST(TensorOpTest, SpaceToDepthTest_1_double) { @@ -111,9 +109,7 @@ TEST(TensorOpTest, SpaceToDepthTest_2) { 88., 103., 106., 68., 71., 86., 89., 104., 107.}; test.AddOutput("output", {2, 27, 1, 2}, result); - // TODO: Test is flaky on QNN EP (CPU backend). - // Re-enable when the QnnCPUBackendTests.DISABLED_SpaceToDepth_Flaky2 test is fixed. - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kQnnExecutionProvider}); + test.Run(OpTester::ExpectResult::kExpectSuccess); } TEST(TensorOpTest, SpaceToDepthTest_3) { @@ -327,8 +323,7 @@ TYPED_TEST(TensorOpTest, DepthToSpaceTest_3) { ORT_THROW("Type not supported"); } - // TODO: Test is flaky on QNN EP (CPU backend). - // Re-enable when the QnnCPUBackendTests.DISABLED_SpaceToDepth_Flaky test is fixed. + // type not supported by QNN EP: MLFloat16 and unsigned char test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kQnnExecutionProvider}); } @@ -392,8 +387,7 @@ TYPED_TEST(TensorOpTest, DepthToSpaceTest_4) { ORT_THROW("Type not supported"); } - // TODO: Test is flaky on QNN EP (CPU backend). - // Re-enable when the QnnCPUBackendTests.DISABLED_SpaceToDepth_Flaky2 test is fixed. + // type not supported by QNN EP: MLFloat16 and unsigned char test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kQnnExecutionProvider}); } @@ -439,8 +433,7 @@ TYPED_TEST(TensorOpTest, DepthToSpaceTest_5) { ORT_THROW("Type not supported"); } - // TODO: Test is flaky on QNN EP (CPU backend). - // Re-enable when the QnnCPUBackendTests.DISABLED_SpaceToDepth_Flaky2 test is fixed. + // type not supported by QNN EP: MLFloat16 and unsigned char test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kQnnExecutionProvider}); } diff --git a/onnxruntime/test/providers/cuda/test_cases/attention_kernel_options_test.cc b/onnxruntime/test/providers/cuda/test_cases/attention_kernel_options_test.cc index b2e986f680763..16139d8b96ffa 100644 --- a/onnxruntime/test/providers/cuda/test_cases/attention_kernel_options_test.cc +++ b/onnxruntime/test/providers/cuda/test_cases/attention_kernel_options_test.cc @@ -10,7 +10,6 @@ #include #include - using onnxruntime::AttentionKernelOptions; using onnxruntime::contrib::attention::AttentionBackend; @@ -30,6 +29,7 @@ TEST(AttentionKernelOptionsTest, NonZeroValue) { ASSERT_FALSE(options.UseTrtFlashAttention()); ASSERT_FALSE(options.UseTrtCrossAttention()); ASSERT_FALSE(options.UseTrtCausalAttention()); + ASSERT_FALSE(options.UseDecoderAttention()); EXPECT_EQ(options.MinSeqLenForFlashAttentionPackedQkv(), 0); EXPECT_EQ(options.MinSeqLenForEfficientAttentionFp32(), 0); } @@ -46,6 +46,7 @@ TEST(AttentionKernelOptionsTest, NonZeroValue) { ASSERT_FALSE(options.UseTrtFlashAttention()); ASSERT_FALSE(options.UseTrtCrossAttention()); ASSERT_FALSE(options.UseTrtCausalAttention()); + ASSERT_FALSE(options.UseDecoderAttention()); EXPECT_EQ(options.MinSeqLenForFlashAttentionPackedQkv(), 0); EXPECT_EQ(options.MinSeqLenForEfficientAttentionFp32(), 0); } @@ -62,6 +63,7 @@ TEST(AttentionKernelOptionsTest, NonZeroValue) { ASSERT_FALSE(options.UseTrtFlashAttention()); ASSERT_FALSE(options.UseTrtCrossAttention()); ASSERT_FALSE(options.UseTrtCausalAttention()); + ASSERT_FALSE(options.UseDecoderAttention()); EXPECT_EQ(options.MinSeqLenForFlashAttentionPackedQkv(), 0); EXPECT_EQ(options.MinSeqLenForEfficientAttentionFp32(), 0); } @@ -78,6 +80,7 @@ TEST(AttentionKernelOptionsTest, NonZeroValue) { ASSERT_TRUE(options.UseTrtFlashAttention()); ASSERT_FALSE(options.UseTrtCrossAttention()); ASSERT_FALSE(options.UseTrtCausalAttention()); + ASSERT_FALSE(options.UseDecoderAttention()); EXPECT_EQ(options.MinSeqLenForFlashAttentionPackedQkv(), 0); EXPECT_EQ(options.MinSeqLenForEfficientAttentionFp32(), 0); } @@ -94,6 +97,24 @@ TEST(AttentionKernelOptionsTest, NonZeroValue) { ASSERT_FALSE(options.UseTrtFlashAttention()); ASSERT_TRUE(options.UseTrtCrossAttention()); ASSERT_TRUE(options.UseTrtCausalAttention()); + ASSERT_FALSE(options.UseDecoderAttention()); + EXPECT_EQ(options.MinSeqLenForFlashAttentionPackedQkv(), 0); + EXPECT_EQ(options.MinSeqLenForEfficientAttentionFp32(), 0); + } + + { + AttentionKernelOptions options; + int value = static_cast(AttentionBackend::DECODER_ATTENTION); + options.InitializeOnce(value, false); + ASSERT_FALSE(options.UseFlashAttention()); + ASSERT_FALSE(options.UseEfficientAttention()); + ASSERT_FALSE(options.UseTrtFusedAttention()); + ASSERT_FALSE(options.UseCudnnFlashAttention()); + ASSERT_FALSE(options.UseUnfusedAttention()); + ASSERT_FALSE(options.UseTrtFlashAttention()); + ASSERT_FALSE(options.UseTrtCrossAttention()); + ASSERT_FALSE(options.UseTrtCausalAttention()); + ASSERT_TRUE(options.UseDecoderAttention()); EXPECT_EQ(options.MinSeqLenForFlashAttentionPackedQkv(), 0); EXPECT_EQ(options.MinSeqLenForEfficientAttentionFp32(), 0); } @@ -110,7 +131,7 @@ TEST(AttentionKernelOptionsTest, NonZeroValue) { {onnxruntime::contrib::attention::kDisableFusedCrossAttention, "0"}, {onnxruntime::contrib::attention::kDisableMemoryEfficientAttention, "0"}, {onnxruntime::contrib::attention::kEnableFusedCausalAttention, "1"}, - {onnxruntime::contrib::attention::kEnableFusedCausalAttention, "1"}}}; + {onnxruntime::contrib::attention::kDisableDecoderAttention, "0"}}}; AttentionKernelOptions options; int value = static_cast(AttentionBackend::FLASH_ATTENTION); options.InitializeOnce(value, false); @@ -122,6 +143,7 @@ TEST(AttentionKernelOptionsTest, NonZeroValue) { ASSERT_FALSE(options.UseTrtFlashAttention()); ASSERT_FALSE(options.UseTrtCrossAttention()); ASSERT_FALSE(options.UseTrtCausalAttention()); + ASSERT_FALSE(options.UseDecoderAttention()); EXPECT_EQ(options.MinSeqLenForFlashAttentionPackedQkv(), 0); EXPECT_EQ(options.MinSeqLenForEfficientAttentionFp32(), 0); } @@ -136,7 +158,7 @@ TEST(AttentionKernelOptionsTest, NonZeroValue) { {onnxruntime::contrib::attention::kDisableFusedCrossAttention, "1"}, {onnxruntime::contrib::attention::kDisableMemoryEfficientAttention, "1"}, {onnxruntime::contrib::attention::kEnableFusedCausalAttention, "0"}, - {onnxruntime::contrib::attention::kEnableFusedCausalAttention, "0"}, + {onnxruntime::contrib::attention::kDisableDecoderAttention, "1"}, {onnxruntime::contrib::attention::kMinSeqLenForFlashAttentionPackedQKV, "128"}, {onnxruntime::contrib::attention::kMinSeqLenForEfficientAttentionFp32, "256"}}}; AttentionKernelOptions options; @@ -150,6 +172,7 @@ TEST(AttentionKernelOptionsTest, NonZeroValue) { ASSERT_FALSE(options.UseTrtFlashAttention()); ASSERT_FALSE(options.UseTrtCrossAttention()); ASSERT_FALSE(options.UseTrtCausalAttention()); + ASSERT_FALSE(options.UseDecoderAttention()); EXPECT_EQ(options.MinSeqLenForFlashAttentionPackedQkv(), 128); EXPECT_EQ(options.MinSeqLenForEfficientAttentionFp32(), 256); } @@ -167,7 +190,7 @@ TEST(AttentionKernelOptionsTest, DefaultOptionWithEnvVar) { {onnxruntime::contrib::attention::kDisableFusedCrossAttention, "0"}, {onnxruntime::contrib::attention::kDisableMemoryEfficientAttention, "0"}, {onnxruntime::contrib::attention::kEnableFusedCausalAttention, "1"}, - {onnxruntime::contrib::attention::kEnableFusedCausalAttention, "1"}, + {onnxruntime::contrib::attention::kDisableDecoderAttention, "0"}, {onnxruntime::contrib::attention::kMinSeqLenForFlashAttentionPackedQKV, "128"}, {onnxruntime::contrib::attention::kMinSeqLenForEfficientAttentionFp32, "256"}}}; AttentionKernelOptions options; @@ -180,7 +203,7 @@ TEST(AttentionKernelOptionsTest, DefaultOptionWithEnvVar) { ASSERT_TRUE(options.UseTrtFlashAttention()); ASSERT_TRUE(options.UseTrtCrossAttention()); ASSERT_TRUE(options.UseTrtCausalAttention()); - ASSERT_TRUE(options.UseTrtCausalAttention()); + ASSERT_TRUE(options.UseDecoderAttention()); EXPECT_EQ(options.MinSeqLenForFlashAttentionPackedQkv(), 128); EXPECT_EQ(options.MinSeqLenForEfficientAttentionFp32(), 256); } @@ -197,7 +220,7 @@ TEST(AttentionKernelOptionsTest, DefaultMinSeqLens) { {onnxruntime::contrib::attention::kEnableCudnnFlashAttention, "0"}, {onnxruntime::contrib::attention::kDisableMemoryEfficientAttention, "1"}, {onnxruntime::contrib::attention::kEnableFusedCausalAttention, "0"}, - {onnxruntime::contrib::attention::kEnableFusedCausalAttention, "0"}}}; + {onnxruntime::contrib::attention::kDisableDecoderAttention, "1"}}}; AttentionKernelOptions options; options.InitializeOnce(value, false); ASSERT_FALSE(options.UseFlashAttention()); @@ -208,7 +231,7 @@ TEST(AttentionKernelOptionsTest, DefaultMinSeqLens) { ASSERT_FALSE(options.UseTrtFlashAttention()); ASSERT_FALSE(options.UseTrtCrossAttention()); ASSERT_FALSE(options.UseTrtCausalAttention()); - ASSERT_FALSE(options.UseTrtCausalAttention()); + ASSERT_FALSE(options.UseDecoderAttention()); EXPECT_EQ(options.MinSeqLenForFlashAttentionPackedQkv(), onnxruntime::contrib::attention::kDefaultMinSeqLenForFlashAttentionPackedQKV); EXPECT_EQ(options.MinSeqLenForEfficientAttentionFp32(), diff --git a/onnxruntime/test/providers/internal_testing/internal_testing_execution_provider.cc b/onnxruntime/test/providers/internal_testing/internal_testing_execution_provider.cc index b753bc386d722..ee0aff6d26444 100644 --- a/onnxruntime/test/providers/internal_testing/internal_testing_execution_provider.cc +++ b/onnxruntime/test/providers/internal_testing/internal_testing_execution_provider.cc @@ -111,6 +111,7 @@ DataLayout InternalTestingExecutionProvider::GetPreferredLayout() const { std::vector> InternalTestingExecutionProvider::GetCapability(const onnxruntime::GraphViewer& graph_viewer, const IKernelLookup& kernel_lookup, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const { // find nodes that have ops in our supported list std::unordered_set supported_static_nodes; diff --git a/onnxruntime/test/providers/internal_testing/internal_testing_execution_provider.h b/onnxruntime/test/providers/internal_testing/internal_testing_execution_provider.h index d2ed8259ee974..0caa0febc2796 100644 --- a/onnxruntime/test/providers/internal_testing/internal_testing_execution_provider.h +++ b/onnxruntime/test/providers/internal_testing/internal_testing_execution_provider.h @@ -20,6 +20,7 @@ class InternalTestingExecutionProvider : public IExecutionProvider { std::vector> GetCapability(const onnxruntime::GraphViewer& graph_view, const IKernelLookup& /*kernel_lookup*/, + const GraphOptimizerRegistry& /* graph_optimizer_registry */, IResourceAccountant* /* resource_accountant */) const override; common::Status Compile(const std::vector& fused_nodes, diff --git a/onnxruntime/test/providers/qnn/argmaxmin_op_test.cc b/onnxruntime/test/providers/qnn/argmaxmin_op_test.cc index 0dd223bca6114..1ee556dfea294 100644 --- a/onnxruntime/test/providers/qnn/argmaxmin_op_test.cc +++ b/onnxruntime/test/providers/qnn/argmaxmin_op_test.cc @@ -44,11 +44,7 @@ static void RunCPUArgMxxOpTest(const std::string& op_type, TestInputDef i int opset = 13) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif + provider_options["backend_type"] = "cpu"; RunQnnModelTest(BuildOpTestCase(op_type, {input_def}, {}, attrs), provider_options, @@ -65,11 +61,7 @@ static void RunQDQArgMxxOpTest(const std::string& op_type, TestInputDef i int opset = 13) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; TestQDQModelAccuracy(BuildOpTestCase(op_type, {input_def}, {}, attrs), // baseline float32 model diff --git a/onnxruntime/test/providers/qnn/average_pool_test.cc b/onnxruntime/test/providers/qnn/average_pool_test.cc index 16dd84ace2e0e..7969f4472629a 100644 --- a/onnxruntime/test/providers/qnn/average_pool_test.cc +++ b/onnxruntime/test/providers/qnn/average_pool_test.cc @@ -26,11 +26,7 @@ static void RunAveragePoolOpTest(const std::string& op_type, ExpectedEPNodeAssignment expected_ep_assignment, int opset = 18) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif + provider_options["backend_type"] = "cpu"; provider_options["offload_graph_io_quantization"] = "0"; RunQnnModelTest(BuildOpTestCase(op_type, input_defs, {}, attrs), @@ -49,11 +45,7 @@ static void RunQDQAveragePoolOpTest(const std::string& op_type, int opset = 18, QDQTolerance tolerance = QDQTolerance()) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; TestQDQModelAccuracy(BuildOpTestCase(op_type, input_defs, {}, attrs), @@ -190,4 +182,4 @@ TEST_F(QnnHTPBackendTests, AveragePool_AutopadSameLower_HTP_u8) { } // namespace test } // namespace onnxruntime -#endif // !defined(ORT_MINIMAL_BUILD) \ No newline at end of file +#endif // !defined(ORT_MINIMAL_BUILD) diff --git a/onnxruntime/test/providers/qnn/batch_norm_htp_test.cc b/onnxruntime/test/providers/qnn/batch_norm_htp_test.cc index 7471b44fafc63..73bb6f2d203c0 100644 --- a/onnxruntime/test/providers/qnn/batch_norm_htp_test.cc +++ b/onnxruntime/test/providers/qnn/batch_norm_htp_test.cc @@ -155,11 +155,7 @@ static void RunBatchNormQDQTest(const TestInputDef& input_def, ExpectedEPNodeAssignment expected_ep_assignment, QDQTolerance tolerance = QDQTolerance()) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; // Runs model with DQ-> InstanceNorm -> Q and compares the outputs of the CPU and QNN EPs. @@ -176,11 +172,7 @@ static void RunBatchNormFP16Test(const TestInputDef& input_def, const TestInputDef& bias_def, ExpectedEPNodeAssignment expected_ep_assignment) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; TestInputDef input_fp16_def = ConvertToFP16InputDef(input_def); @@ -277,12 +269,7 @@ TEST_F(QnnHTPBackendTests, BatchNorm_FP16) { TEST_F(QnnHTPBackendTests, BatchNorm_FP32_as_FP16) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif - + provider_options["backend_type"] = "htp"; provider_options["enable_htp_fp16_precision"] = "1"; constexpr int64_t num_channels = 2; diff --git a/onnxruntime/test/providers/qnn/cast_test.cc b/onnxruntime/test/providers/qnn/cast_test.cc index 3a90a6db6d5c0..2326b2949a6bd 100644 --- a/onnxruntime/test/providers/qnn/cast_test.cc +++ b/onnxruntime/test/providers/qnn/cast_test.cc @@ -52,11 +52,7 @@ static void RunCastOpTest(const std::vector& shape, ONNX_NAMESPACE::Ten bool use_htp, bool enable_fp16_precision = true) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = use_htp ? "QnnHtp.dll" : "QnnCpu.dll"; -#else - provider_options["backend_path"] = use_htp ? "libQnnHtp.so" : "libQnnCpu.so"; -#endif + provider_options["backend_type"] = use_htp ? "htp" : "cpu"; provider_options["offload_graph_io_quantization"] = "0"; if (use_htp && enable_fp16_precision) { @@ -134,4 +130,4 @@ TEST_F(QnnHTPBackendTests, TestCastInt32ToInt64HTP) { } // namespace test } // namespace onnxruntime -#endif // !defined(ORT_MINIMAL_BUILD) \ No newline at end of file +#endif // !defined(ORT_MINIMAL_BUILD) diff --git a/onnxruntime/test/providers/qnn/clip_op_test.cc b/onnxruntime/test/providers/qnn/clip_op_test.cc index 2ac34acbf16e2..512403bc5a10b 100644 --- a/onnxruntime/test/providers/qnn/clip_op_test.cc +++ b/onnxruntime/test/providers/qnn/clip_op_test.cc @@ -24,12 +24,7 @@ static void RunClipTest(const TestInputDef& input_def, int opset = 13, bool enable_fp16_precision = true) { ProviderOptions provider_options; - -#if defined(_WIN32) - provider_options["backend_path"] = on_cpu_backend ? "QnnCpu.dll" : "QnnHtp.dll"; -#else - provider_options["backend_path"] = on_cpu_backend ? "libQnnCpu.so" : "libQnnHtp.so"; -#endif + provider_options["backend_type"] = on_cpu_backend ? "cpu" : "htp"; if (!on_cpu_backend && enable_fp16_precision) { provider_options["enable_htp_fp16_precision"] = "1"; @@ -111,12 +106,7 @@ static void RunQDQClipTestOnHTP(const TestInputDef& input_def, int opset = 13, bool use_contrib_qdq = false) { ProviderOptions provider_options; - -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; auto f32_model_builder = BuildOpTestCase("Clip", {input_def}, {min_max_defs}, {}); @@ -200,12 +190,7 @@ TEST_F(QnnHTPBackendTests, Clip_U8_Rank5) { }; ProviderOptions provider_options; - -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; RunQnnModelTest(model_fn, @@ -217,12 +202,7 @@ TEST_F(QnnHTPBackendTests, Clip_U8_Rank5) { // Test FP16 Clip with min (FP16) TEST_F(QnnHTPBackendTests, Clip_FP16) { ProviderOptions provider_options; - -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; auto f32_input = TestInputDef({1, 3, 2, 2}, false, {-10.0f, -8.0f, -3.5f, 2.2f, diff --git a/onnxruntime/test/providers/qnn/conv_test.cc b/onnxruntime/test/providers/qnn/conv_test.cc index d12141fccc6dd..b15042a808c37 100644 --- a/onnxruntime/test/providers/qnn/conv_test.cc +++ b/onnxruntime/test/providers/qnn/conv_test.cc @@ -87,12 +87,7 @@ static void RunCPUConvOpTest(const std::string& conv_op_type, const TestInputDef int opset = 13, float fp32_abs_err = 1e-5f) { ProviderOptions provider_options; - -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif + provider_options["backend_type"] = "cpu"; provider_options["offload_graph_io_quantization"] = "0"; auto build_fn = BuildF32ConvTestCase(conv_op_type, input_def, weights_def, bias_def, strides, pads, @@ -313,12 +308,7 @@ static void RunHTPConvOpTest(const std::string& conv_op_type, const TestInputDef QDQTolerance tolerance = QDQTolerance(), std::optional output_activation = std::nullopt) { ProviderOptions provider_options; - -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; TestQDQModelAccuracy(BuildF32ConvTestCase(conv_op_type, input_def, weights_def, bias_def, strides, pads, dilations, @@ -351,12 +341,7 @@ static void RunHTPConvOpPerChannelTest(const std::string& conv_op_type, const Te QDQTolerance tolerance = QDQTolerance(), std::optional output_activation = std::nullopt) { ProviderOptions provider_options; - -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; auto f32_fn = BuildF32ConvTestCase(conv_op_type, input_def, weights_def, bias_def, strides, pads, dilations, @@ -371,7 +356,8 @@ static void RunHTPConvOpPerChannelTest(const std::string& conv_op_type, const Te // Check that QNN compiles DQ -> Conv -> Q as a single unit. // Tests bias as a dynamic input. // TODO: Segfaults when calling graphFinalize(). v2.13 -TEST_F(QnnCPUBackendTests, DISABLED_Convf32_dynamic_bias) { +// fixed by QNN 2.32 +TEST_F(QnnCPUBackendTests, Convf32_dynamic_bias) { RunCPUConvOpTest("Conv", TestInputDef({1, 1, 3, 3}, false, 0.0f, 10.0f), // Random dynamic input TestInputDef({2, 1, 2, 2}, true, 0.0f, 1.0f), // Random static weights @@ -499,7 +485,8 @@ TEST_F(QnnCPUBackendTests, Convf32_AutoPadLower) { // Tests ConvTranspose's auto_pad value "SAME_LOWER" (compares to CPU EP). // 2.31 Exception from qnn_interface.graphAddNode // unknown file: error: SEH exception with code 0xc0000005 thrown in the test body -TEST_F(QnnCPUBackendTests, DISABLED_ConvTransposef32_AutoPadLower) { +// fixed by QNN 2.32 +TEST_F(QnnCPUBackendTests, ConvTransposef32_AutoPadLower) { RunCPUConvOpTest("ConvTranspose", TestInputDef({1, 1, 3, 3}, false, -3.0f, 3.0f), // Random dynamic input TestInputDef({1, 2, 2, 2}, false, -1.0f, 1.0f), // Random dynamic weights @@ -516,7 +503,8 @@ TEST_F(QnnCPUBackendTests, DISABLED_ConvTransposef32_AutoPadLower) { // Exception from graphFinalize // Exception thrown at 0x00007FFFB7651630 (QnnCpu.dll) in onnxruntime_test_all.exe: // 0xC0000005: Access violation reading location 0x0000000000000000. -TEST_F(QnnCPUBackendTests, DISABLED_ConvTranspose3D_f32_AutoPadLower) { +// fixed by QNN 2.32 +TEST_F(QnnCPUBackendTests, ConvTranspose3D_f32_AutoPadLower) { RunCPUConvOpTest("ConvTranspose", TestInputDef({1, 1, 3, 3, 3}, false, -3.0f, 3.0f), // Random dynamic input TestInputDef({1, 2, 2, 2, 2}, false, -1.0f, 1.0f), // Random dynamic weights @@ -642,7 +630,8 @@ TEST_F(QnnCPUBackendTests, ConvTranspose1Df32_StaticWeights_DefaultBias) { // Test 1D ConvTranspose with dynamic weights (implemented in QNN EP as 2D convolution with height of 1). // 2.31 Exception from qnn_interface.graphAddNode // unknown file: error: SEH exception with code 0xc0000005 thrown in the test body -TEST_F(QnnCPUBackendTests, DISABLED_ConvTranspose1Df32_DynamicWeights_DefaultBias) { +// fixed by QNN 2.32 +TEST_F(QnnCPUBackendTests, ConvTranspose1Df32_DynamicWeights_DefaultBias) { std::vector input_data = {0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f}; RunCPUConvOpTest("ConvTranspose", TestInputDef({1, 2, 4}, false, input_data), // Dynamic input @@ -667,12 +656,7 @@ TEST_F(QnnCPUBackendTests, DISABLED_ConvTranspose1Df32_DynamicWeights_DefaultBia // So, Conv gets processed before Mul node TEST_F(QnnHTPBackendTests, Test_QDQConvWithDynamicWeightsFromMul) { ProviderOptions provider_options; - -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; auto BuildConvMulGraph = [](ModelTestBuilder& builder) { diff --git a/onnxruntime/test/providers/qnn/flatten_op_test.cc b/onnxruntime/test/providers/qnn/flatten_op_test.cc index 9c87fae512b72..da2d452c788cf 100644 --- a/onnxruntime/test/providers/qnn/flatten_op_test.cc +++ b/onnxruntime/test/providers/qnn/flatten_op_test.cc @@ -22,12 +22,7 @@ static void RunFlattenTestOnCPU(const TestInputDef& input_def, ExpectedEPNodeAssignment expected_ep_assignment, int opset = 13) { ProviderOptions provider_options; - -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif + provider_options["backend_type"] = "cpu"; RunQnnModelTest(BuildOpTestCase("Flatten", {input_def}, {}, attrs), provider_options, @@ -73,12 +68,7 @@ static void RunFlattenTestOnHTP(const TestInputDef& input_def, ExpectedEPNodeAssignment expected_ep_assignment, int opset = 13) { ProviderOptions provider_options; - -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; RunQnnModelTest(BuildOpTestCase("Flatten", {input_def}, {}, attrs), provider_options, @@ -95,12 +85,7 @@ static void RunQDQFlattenTestOnHTP(const TestInputDef& input_def, int opset = 13, bool use_contrib_qdq = false) { ProviderOptions provider_options; - -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; auto f32_model_builder = BuildOpTestCase("Flatten", {input_def}, {}, attrs); @@ -167,12 +152,7 @@ TEST_F(QnnHTPBackendTests, Flatten_QDQ8bit_Rank5) { }; ProviderOptions provider_options; - -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; RunQnnModelTest(model_fn, diff --git a/onnxruntime/test/providers/qnn/gather_elems_op_test.cc b/onnxruntime/test/providers/qnn/gather_elems_op_test.cc index 4cce75d6927df..9036410139b48 100644 --- a/onnxruntime/test/providers/qnn/gather_elems_op_test.cc +++ b/onnxruntime/test/providers/qnn/gather_elems_op_test.cc @@ -62,11 +62,7 @@ static void RunCPUGatherElemsOpTest(const TestInputDef& input_def, ProviderOptions provider_options; float fp32_abs_err = 1e-5f; // default tolerance -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif + provider_options["backend_type"] = "cpu"; provider_options["offload_graph_io_quantization"] = "0"; RunQnnModelTest(BuildOpTestCase("GatherElements", {input_def}, {indices_def}, attrs), @@ -87,11 +83,7 @@ static void RunHTPQDQGatherElemsOpTest(const TestInputDef& input_def, bool use_contrib_qdq = false) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; auto f32_model_builder = BuildOpTestCase("GatherElements", {input_def}, {indices_def}, attrs); @@ -116,11 +108,7 @@ static void RunHTPGatherElemsOpTest(const TestInputDef& input_def, ProviderOptions provider_options; float fp32_abs_err = 1e-5f; // default tolerance -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; RunQnnModelTest(BuildOpTestCase("GatherElements", {input_def}, {indices_def}, attrs), diff --git a/onnxruntime/test/providers/qnn/gather_op_htp_test.cc b/onnxruntime/test/providers/qnn/gather_op_htp_test.cc index 3db96ddb548d2..326354dffa8ae 100644 --- a/onnxruntime/test/providers/qnn/gather_op_htp_test.cc +++ b/onnxruntime/test/providers/qnn/gather_op_htp_test.cc @@ -58,11 +58,7 @@ static void RunQDQGatherOpTest(const TestInputDef& input_def, ExpectedEPNodeAssignment expected_ep_assignment, bool use_contrib_qdq = false) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; auto f32_model_builder = BuildOpTestCase("Gather", {input_def}, {indices_def}, attrs); @@ -170,11 +166,7 @@ static void RunOpTest(const std::string& op_type, const std::string& op_domain = kOnnxDomain, float fp32_abs_err = 1e-3f) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; // Runs model with a Q/DQ binary op and compares the outputs of the CPU and QNN EPs. @@ -199,4 +191,4 @@ TEST_F(QnnHTPBackendTests, GatherOp_IndicesStaticInt64) { } // namespace test } // namespace onnxruntime -#endif \ No newline at end of file +#endif diff --git a/onnxruntime/test/providers/qnn/gemm_op_test.cc b/onnxruntime/test/providers/qnn/gemm_op_test.cc index 4d82578cb8536..a7c86806bf426 100644 --- a/onnxruntime/test/providers/qnn/gemm_op_test.cc +++ b/onnxruntime/test/providers/qnn/gemm_op_test.cc @@ -24,11 +24,7 @@ static void RunGemmTestOnCPU(const std::vector>& input_de int opset = 13) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif + provider_options["backend_type"] = "cpu"; provider_options["offload_graph_io_quantization"] = "0"; RunQnnModelTest(BuildOpTestCase("Gemm", input_defs, {}, attrs), @@ -198,11 +194,7 @@ void RunCPUReshapeGemmTest(const TestInputDef& input, const TestInputDef< ExpectedEPNodeAssignment expected_ep_assignment, float fp32_abs_err = 1e-5f) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif + provider_options["backend_type"] = "cpu"; auto build_fn = BuildReshapeGemmTestCase(input, shape, weight, bias); RunQnnModelTest(build_fn, provider_options, 18, expected_ep_assignment, fp32_abs_err); } @@ -283,11 +275,7 @@ static void RunQDQGemmTestOnHTP(const std::vector>& input_de QDQTolerance tolerance = QDQTolerance()) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; auto f32_model_builder = BuildOpTestCase("Gemm", input_defs, {}, attrs); diff --git a/onnxruntime/test/providers/qnn/instance_norm_htp_test.cc b/onnxruntime/test/providers/qnn/instance_norm_htp_test.cc index d4f66b72e0a4c..4823b152b0269 100644 --- a/onnxruntime/test/providers/qnn/instance_norm_htp_test.cc +++ b/onnxruntime/test/providers/qnn/instance_norm_htp_test.cc @@ -74,11 +74,7 @@ static void RunInstanceNormQDQTest(const TestInputDef& input_def, ExpectedEPNodeAssignment expected_ep_assignment, bool use_contrib_qdq = false) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; // Runs model with DQ-> InstanceNorm -> Q and compares the outputs of the CPU and QNN EPs. diff --git a/onnxruntime/test/providers/qnn/layer_norm_test.cc b/onnxruntime/test/providers/qnn/layer_norm_test.cc index b2997c627827d..182877ddf200c 100644 --- a/onnxruntime/test/providers/qnn/layer_norm_test.cc +++ b/onnxruntime/test/providers/qnn/layer_norm_test.cc @@ -23,11 +23,7 @@ static void RunLayerNormCpuTest(const TestInputDef& input_def, const std::vector& attrs, ExpectedEPNodeAssignment expected_ep_assignment) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif + provider_options["backend_type"] = "cpu"; provider_options["offload_graph_io_quantization"] = "0"; RunQnnModelTest(BuildOpTestCase("LayerNormalization", {input_def, scale_def}, {}, attrs), @@ -148,11 +144,7 @@ static void RunLayerNormQDQTest(const TestInputDef& input_def, ExpectedEPNodeAssignment expected_ep_assignment, bool use_contrib_qdq_ops = false) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; TestQDQModelAccuracy(BuildOpTestCase("LayerNormalization", {input_def, scale_def}, {}, attrs), diff --git a/onnxruntime/test/providers/qnn/leakyrelu_op_htp_test.cc b/onnxruntime/test/providers/qnn/leakyrelu_op_htp_test.cc index 77d96b56d23ef..ec85fd3dd339d 100644 --- a/onnxruntime/test/providers/qnn/leakyrelu_op_htp_test.cc +++ b/onnxruntime/test/providers/qnn/leakyrelu_op_htp_test.cc @@ -23,11 +23,7 @@ static void RunLeakyReluOpQDQTest(const TestInputDef& input_def, int opset, ExpectedEPNodeAssignment expected_ep_assignment) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; TestQDQModelAccuracy(BuildOpTestCase("LeakyRelu", {input_def}, {}, attrs), @@ -62,11 +58,7 @@ TEST_F(QnnHTPBackendTests, LeakyReluOpSet16) { // Test Leaky Relu where input is FP16 and alpha is FP32 TEST_F(QnnHTPBackendTests, LeakyReluFP16OpSet16) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; auto input_def = TestInputDef({1, 2, 3}, false, {-40.0f, -20.0f, 1.0f, 10.0f, 30.0f, 40.0f}); @@ -83,4 +75,4 @@ TEST_F(QnnHTPBackendTests, LeakyReluFP16OpSet16) { } // namespace test } // namespace onnxruntime -#endif \ No newline at end of file +#endif diff --git a/onnxruntime/test/providers/qnn/logical_comp_ops_test.cc b/onnxruntime/test/providers/qnn/logical_comp_ops_test.cc index eca018c4b5ded..18e19efca13d7 100644 --- a/onnxruntime/test/providers/qnn/logical_comp_ops_test.cc +++ b/onnxruntime/test/providers/qnn/logical_comp_ops_test.cc @@ -68,11 +68,7 @@ static void RunCPULogicalOpTest(const std::string& op_type, const std::vector(op_type, shape), @@ -154,11 +146,7 @@ TEST_F(QnnHTPBackendTests, LogicalOpLessOrEqual4D) { // Tests a QDQ graph with an Equal node followed by a Cast. TEST_F(QnnHTPBackendTests, EqualToCast4D) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; // Model building function that creates a QDQ graph with an Equal node followed by diff --git a/onnxruntime/test/providers/qnn/lrn_op_test.cc b/onnxruntime/test/providers/qnn/lrn_op_test.cc index 1744be53d5caa..bb3a40a47a750 100644 --- a/onnxruntime/test/providers/qnn/lrn_op_test.cc +++ b/onnxruntime/test/providers/qnn/lrn_op_test.cc @@ -64,12 +64,11 @@ static void RunCPULRNOpTest(const TestInputDef& input_def, int64_t size, ProviderOptions provider_options; float fp32_abs_err = 1e-5f; // default tolerance -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; +#if !defined(_WIN32) fp32_abs_err = 1.5e-5f; // On linux we need slightly larger tolerance. #endif + + provider_options["backend_type"] = "cpu"; provider_options["offload_graph_io_quantization"] = "0"; RunQnnModelTest(BuildLRNTestCase(input_def, size, alpha, beta, bias), @@ -87,11 +86,7 @@ static void RunQDQLRNOpTest(const TestInputDef& input_def, int64_t size, float alpha = 0.0001f, float beta = 0.75f, float bias = 1.0f, int opset = 13, QDQTolerance tolerance = QDQTolerance()) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; TestQDQModelAccuracy(BuildLRNTestCase(input_def, size, alpha, beta, bias), diff --git a/onnxruntime/test/providers/qnn/matmul_test.cpp b/onnxruntime/test/providers/qnn/matmul_test.cpp index acc653d8bd459..09ead72889bca 100644 --- a/onnxruntime/test/providers/qnn/matmul_test.cpp +++ b/onnxruntime/test/providers/qnn/matmul_test.cpp @@ -31,19 +31,7 @@ static void RunMatMulOpTest(bool is_htp_backend, const std::vector& sha ExpectedEPNodeAssignment expected_ep_assignment = ExpectedEPNodeAssignment::All, int opset = 18, float f32_abs_err = 1e-4f) { ProviderOptions provider_options; - if (is_htp_backend) { -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif - } else { -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif - } + provider_options["backend_type"] = is_htp_backend ? "htp" : "cpu"; provider_options["offload_graph_io_quantization"] = "0"; RunQnnModelTest(BuildMatMulOpTestCase( @@ -136,13 +124,10 @@ template static void RunQDQMatMulOpTest(const std::vector& shape_0, const std::vector& shape_1, bool is_initializer_0, bool is_initializer_1, ExpectedEPNodeAssignment expected_ep_assignment = ExpectedEPNodeAssignment::All, - int opset = 21, bool use_contrib_qdq = false) { + int opset = 21, bool use_contrib_qdq = false, + QDQTolerance tolerance = QDQTolerance()) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; TestInputDef input0_def( @@ -159,7 +144,7 @@ static void RunQDQMatMulOpTest(const std::vector& shape_0, const std::v TestQDQModelAccuracy( BuildMatMulOpTestCase(input0_def, input1_def), BuildMatMulOpQDQTestCase(input0_def, input1_def, use_contrib_qdq), - provider_options, opset, expected_ep_assignment); + provider_options, opset, expected_ep_assignment, tolerance); } template @@ -169,11 +154,7 @@ static void RunQDQPerChannelMatMulOpTest( ExpectedEPNodeAssignment expected_ep_assignment = ExpectedEPNodeAssignment::All, int opset = 21, bool use_contrib_qdq = false, bool enable_fp16_precision = true) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; if (enable_fp16_precision) { @@ -279,7 +260,8 @@ TEST_F(QnnHTPBackendTests, MatMulOp_QDQ) { // RunQDQMatMulOpTest(shape_0, shape_1, is_initializer_0, is_initializer_1, expected_ep_assignment, opset, // use_contrib_qdq) RunQDQMatMulOpTest({2, 3}, {3, 2}, false, false); - RunQDQMatMulOpTest({2, 3}, {3, 2}, false, true); + RunQDQMatMulOpTest({2, 3}, {3, 2}, false, true, ExpectedEPNodeAssignment::All, 21, + false, QDQTolerance(0.008f)); RunQDQMatMulOpTest({2, 2, 3}, {3, 2}, true, false, ExpectedEPNodeAssignment::All, 18, true); RunQDQMatMulOpTest({2, 1, 3, 3}, {3, 3, 2}, false, true); @@ -312,11 +294,7 @@ TEST_F(QnnHTPBackendTests, MatMulOp_QDQ) { // Got specific shapes and input ranges (quant params) from customer model. TEST_F(QnnHTPBackendTests, MatMulOp_QDQ_Regression_uint16_dynamic_inputs) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; // Test with rank 4 inputs diff --git a/onnxruntime/test/providers/qnn/max_min_op_test.cc b/onnxruntime/test/providers/qnn/max_min_op_test.cc index c7f5eaa0a0af5..bea2e807d4453 100644 --- a/onnxruntime/test/providers/qnn/max_min_op_test.cc +++ b/onnxruntime/test/providers/qnn/max_min_op_test.cc @@ -21,11 +21,7 @@ static void RunCPUMinOrMaxOpTest(const std::string& op_type, int opset = 13) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif + provider_options["backend_type"] = "cpu"; provider_options["offload_graph_io_quantization"] = "0"; RunQnnModelTest(BuildOpTestCase(op_type, input_defs, {}, {}, kOnnxDomain), @@ -43,11 +39,7 @@ static void RunQDQMinOrMaxOpTest(const std::string& op_type, int opset = 13) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; TestQDQModelAccuracy(BuildOpTestCase(op_type, input_defs, {}, {}, kOnnxDomain), // baseline float32 model diff --git a/onnxruntime/test/providers/qnn/pad_op_test.cpp b/onnxruntime/test/providers/qnn/pad_op_test.cpp index ae8c4428e242d..e0bf18a350dff 100644 --- a/onnxruntime/test/providers/qnn/pad_op_test.cpp +++ b/onnxruntime/test/providers/qnn/pad_op_test.cpp @@ -103,19 +103,7 @@ static void RunPadOpTest(const TestInputDef& data_def, bool enable_fp16_precision = false, float f32_abs_err = 1e-5f) { ProviderOptions provider_options; - if (use_htp) { -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif - } else { -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif - } + provider_options["backend_type"] = use_htp ? "htp" : "cpu"; provider_options["offload_graph_io_quantization"] = "0"; if (enable_fp16_precision) { @@ -140,11 +128,7 @@ static void RunQDQPadOpTest(const TestInputDef& data_def, bool constant_value_quantized = true, int opset = 18) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; TestQDQModelAccuracy(BuildPadTestCase(data_def, pads_def, constant_value_def, attrs), @@ -180,7 +164,8 @@ TEST_F(QnnCPUBackendTests, Pad2dPadsNotIni) { // Pad reflect mode // Expected: contains 12 values, where each value and its corresponding value in 16-byte object <0C-00 00-00 00-00 00-00 40-01 23-05 EC-01 00-00> are an almost-equal pair // Actual: 16-byte object <0C-00 00-00 00-00 00-00 40-01 12-05 EC-01 00-00>, where the value pair (1.2, 0) at index #1 don't match, which is -1.2 from 1.2 -TEST_F(QnnCPUBackendTests, DISABLED_PadModeReflect) { +// fixed by QNN 2.32 +TEST_F(QnnCPUBackendTests, PadModeReflect) { bool has_constant_value = false; RunPadOpTest(TestInputDef({3, 2}, false, {1.0f, 1.2f, 2.3f, 3.4f, 4.5f, 5.6f}), TestInputDef({4}, true, {0, 1, 0, 0}), @@ -436,4 +421,4 @@ TEST_F(QnnHTPBackendTests, Pad5d) { } // namespace test } // namespace onnxruntime -#endif // !defined(ORT_MINIMAL_BUILD) \ No newline at end of file +#endif // !defined(ORT_MINIMAL_BUILD) diff --git a/onnxruntime/test/providers/qnn/pool_op_test.cpp b/onnxruntime/test/providers/qnn/pool_op_test.cpp index 76399b413f97b..ae194bd2ef920 100644 --- a/onnxruntime/test/providers/qnn/pool_op_test.cpp +++ b/onnxruntime/test/providers/qnn/pool_op_test.cpp @@ -55,11 +55,7 @@ static void RunPoolOpTest(const std::string& op_type, ExpectedEPNodeAssignment expected_ep_assignment, int opset = 18) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif + provider_options["backend_type"] = "cpu"; provider_options["offload_graph_io_quantization"] = "0"; RunQnnModelTest(BuildOpTestCase(op_type, {input_def}, {}, attrs), @@ -79,11 +75,7 @@ static void RunQDQPoolOpTest(const std::string& op_type, bool use_contrib_qdq_ops = false, QDQTolerance tolerance = QDQTolerance()) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; TestQDQModelAccuracy(BuildOpTestCase(op_type, {input_def}, {}, attrs), @@ -300,4 +292,4 @@ TEST_F(QnnHTPBackendTests, GlobalMaxPool_LargeInput2_u8) { } // namespace test } // namespace onnxruntime -#endif // !defined(ORT_MINIMAL_BUILD) \ No newline at end of file +#endif // !defined(ORT_MINIMAL_BUILD) diff --git a/onnxruntime/test/providers/qnn/qnn_basic_test.cc b/onnxruntime/test/providers/qnn/qnn_basic_test.cc index 0b51b6f8e503d..ae976c164734b 100644 --- a/onnxruntime/test/providers/qnn/qnn_basic_test.cc +++ b/onnxruntime/test/providers/qnn/qnn_basic_test.cc @@ -222,6 +222,29 @@ TEST(QnnEP, TestDisableCPUFallback_ConflictingConfig) { } } +TEST(QnnEP, TestInvalidSpecificationOfBothBackendTypeAndBackendPath) { + onnxruntime::ProviderOptions provider_options{}; + provider_options["backend_type"] = "cpu"; +#if defined(_WIN32) + provider_options["backend_path"] = "QnnCpu.dll"; +#else + provider_options["backend_path"] = "libQnnCpu.so"; +#endif + + Ort::SessionOptions so{}; + so.AppendExecutionProvider("QNN", provider_options); + + const ORTCHAR_T* ort_model_path = ORT_MODEL_FOLDER "constant_floats.onnx"; + + try { + Ort::Session session(*ort_env, ort_model_path, so); + FAIL(); + } catch (const Ort::Exception& e) { + ASSERT_EQ(e.GetOrtErrorCode(), ORT_FAIL); + ASSERT_THAT(e.what(), testing::HasSubstr("Only one of 'backend_type' and 'backend_path' should be set.")); + } +} + // Conv node `Conv` is not supported: GetFileLength for conv_qdq_external_ini.bin failed:open file conv_qdq_external_ini.bin fail, // errcode = 2 - The system cannot find the file specified. TEST_F(QnnHTPBackendTests, TestConvWithExternalData) { diff --git a/onnxruntime/test/providers/qnn/qnn_ep_context_test.cc b/onnxruntime/test/providers/qnn/qnn_ep_context_test.cc index 07843c30a61df..e39102a21dd1c 100644 --- a/onnxruntime/test/providers/qnn/qnn_ep_context_test.cc +++ b/onnxruntime/test/providers/qnn/qnn_ep_context_test.cc @@ -43,6 +43,35 @@ static const std::string& GetNodeAttr(const Node& node, const std::string& attr_ return default_val; } +// from the context cache Onnx model, find the EPContext node with main_context=1, +// and get the QNN context binary file name +static void GetContextBinaryFileName(const std::string onnx_ctx_file, + std::string& last_ctx_bin_file, + const Logger& logger) { + std::shared_ptr ctx_model; + ASSERT_STATUS_OK(Model::Load(ToPathString(onnx_ctx_file), ctx_model, nullptr, logger)); + auto& ctx_graph = ctx_model->MainGraph(); + for (auto& node : ctx_graph.Nodes()) { + if (node.OpType() == "EPContext") { + int64_t is_main_context = GetNodeAttr(node, "main_context", static_cast(0)); + if (1 == is_main_context) { + last_ctx_bin_file = GetNodeAttr(node, "ep_cache_context", ""); + return; + } + } + } +} + +// Get context binary file name from Context model file and remove it with the context model file +void CleanUpCtxFile(std::string context_file_path) { + std::string qnn_ctx_binary_file_name; + GetContextBinaryFileName(context_file_path, qnn_ctx_binary_file_name, + DefaultLoggingManager().DefaultLogger()); + + ASSERT_EQ(std::remove(qnn_ctx_binary_file_name.c_str()), 0); + ASSERT_EQ(std::remove(context_file_path.c_str()), 0); +} + // Create a model with FusedMatMul + Add (quantized) // input1 -> Add -> Q -> DQ ---- // | @@ -123,22 +152,22 @@ void QnnContextBinaryMultiPartitionTestBody(bool single_ep_node = true) { const auto model_data_span = AsByteSpan(model_data.data(), model_data.size()); - const std::string context_binary_file = "./qnn_context_binary_multi_partition_test.onnx"; - std::remove(context_binary_file.c_str()); + const std::string context_model_file = "./qnn_context_binary_multi_partition_test.onnx"; + std::remove(context_model_file.c_str()); Ort::SessionOptions so; so.AddConfigEntry(kOrtSessionOptionEpContextEnable, "1"); - so.AddConfigEntry(kOrtSessionOptionEpContextFilePath, context_binary_file.c_str()); + so.AddConfigEntry(kOrtSessionOptionEpContextFilePath, context_model_file.c_str()); so.AppendExecutionProvider("QNN", provider_options); Ort::Session session(*ort_env, model_data_span.data(), model_data_span.size(), so); // Make sure the Qnn context cache binary file is generated - EXPECT_TRUE(std::filesystem::exists(context_binary_file.c_str())); + EXPECT_TRUE(std::filesystem::exists(context_model_file.c_str())); int ep_context_node_count = 0; int non_ep_context_node_count = 0; std::shared_ptr ctx_model; - ASSERT_STATUS_OK(Model::Load(ToPathString(context_binary_file), ctx_model, nullptr, DefaultLoggingManager().DefaultLogger())); + ASSERT_STATUS_OK(Model::Load(ToPathString(context_model_file), ctx_model, nullptr, DefaultLoggingManager().DefaultLogger())); auto& ctx_graph = ctx_model->MainGraph(); for (auto& node : ctx_graph.Nodes()) { if (node.OpType() == "EPContext") { @@ -156,7 +185,7 @@ void QnnContextBinaryMultiPartitionTestBody(bool single_ep_node = true) { Ort::SessionOptions so2; // context file path is required if it's non-embed mode and the model is loaded from memory - so2.AddConfigEntry(kOrtSessionOptionEpContextFilePath, context_binary_file.c_str()); + so2.AddConfigEntry(kOrtSessionOptionEpContextFilePath, context_model_file.c_str()); so2.AppendExecutionProvider("QNN", provider_options); std::string ctx_model_data; @@ -164,7 +193,7 @@ void QnnContextBinaryMultiPartitionTestBody(bool single_ep_node = true) { Ort::Session session2(*ort_env, ctx_model_data.data(), ctx_model_data.size(), so2); // clean up - ASSERT_EQ(std::remove(context_binary_file.c_str()), 0); + CleanUpCtxFile(context_model_file); } // Test that models with 1 non-quantized FusedMatMul node and 1 quantized Add node can still generate the context binary @@ -237,7 +266,7 @@ void EpCtxCpuNodeWithExternalIniFileTestBody(bool expect_external_ini_file) { // clean up ASSERT_EQ(std::remove(model_with_ext.c_str()), 0); ASSERT_EQ(std::remove(model_ext_file_full_path.c_str()), 0); - ASSERT_EQ(std::remove(ep_context_model_file.c_str()), 0); + CleanUpCtxFile(ep_context_model_file); } // Set the external initializer size threshold to 1024 so FusedMatMul (which fallback on CPU) @@ -333,7 +362,7 @@ TEST_F(QnnHTPBackendTests, QnnContextBinaryGenerationNoOverWrite) { const auto model_data_span = AsByteSpan(model_data.data(), model_data.size()); const std::string ep_context_onnx_file = "./ep_context_no_over_write.onnx"; - const std::string ep_context_binary_file = "./ep_context_no_over_write.onnx_QNNExecutionProvider_QNN_10880527342279992768_1_0.bin"; + const std::string ep_context_binary_file = "./ep_context_no_over_write_QNN_10880527342279992768_1_0.bin"; std::remove(ep_context_onnx_file.c_str()); Ort::SessionOptions so; @@ -444,21 +473,21 @@ TEST_F(QnnHTPBackendTests, QnnContextBinaryGeneration2InputTypes) { const auto model_data_span = AsByteSpan(model_data.data(), model_data.size()); - const std::string context_binary_file = "./qnn_context_binary_int32_fp32_inputs_test.onnx"; - std::remove(context_binary_file.c_str()); + const std::string context_model_file = "./qnn_context_binary_int32_fp32_inputs_test.onnx"; + std::remove(context_model_file.c_str()); Ort::SessionOptions so; so.AddConfigEntry(kOrtSessionOptionEpContextEnable, "1"); - so.AddConfigEntry(kOrtSessionOptionEpContextFilePath, context_binary_file.c_str()); + so.AddConfigEntry(kOrtSessionOptionEpContextFilePath, context_model_file.c_str()); so.AppendExecutionProvider("QNN", provider_options); Ort::Session session(*ort_env, model_data_span.data(), model_data_span.size(), so); // Make sure the Qnn context cache binary file is generated - EXPECT_TRUE(std::filesystem::exists(context_binary_file.c_str())); + EXPECT_TRUE(std::filesystem::exists(context_model_file.c_str())); // clean up - ASSERT_EQ(std::remove(context_binary_file.c_str()), 0); + CleanUpCtxFile(context_model_file); } // Generate context cache model from the ONNX models with 2 inputs. @@ -481,26 +510,26 @@ TEST_F(QnnHTPBackendTests, QnnContextGeneration2InputsOrderIssue) { auto& logging_manager = DefaultLoggingManager(); logging_manager.SetDefaultLoggerSeverity(logging::Severity::kERROR); - const std::string context_binary_file = "./qnn_ctx_2_inputs_order_test_gen.onnx"; + const std::string context_model_file = "./qnn_ctx_2_inputs_order_test_gen.onnx"; Ort::SessionOptions so; so.AddConfigEntry(kOrtSessionOptionEpContextEnable, "1"); - so.AddConfigEntry(kOrtSessionOptionEpContextFilePath, context_binary_file.c_str()); + so.AddConfigEntry(kOrtSessionOptionEpContextFilePath, context_model_file.c_str()); so.AppendExecutionProvider("QNN", provider_options); Ort::Session session(*ort_env, ORT_TSTR("testdata/qnn_ctx_2_inputs_order_test.onnx"), so); // Make sure the Qnn context cache binary file is generated - EXPECT_TRUE(std::filesystem::exists(context_binary_file.c_str())); + EXPECT_TRUE(std::filesystem::exists(context_model_file.c_str())); std::shared_ptr model; - ASSERT_STATUS_OK(Model::Load(ToPathString(context_binary_file), model, nullptr, DefaultLoggingManager().DefaultLogger())); + ASSERT_STATUS_OK(Model::Load(ToPathString(context_model_file), model, nullptr, DefaultLoggingManager().DefaultLogger())); auto inputs = model->MainGraph().GetInputs(); EXPECT_TRUE(inputs.size() == 2); EXPECT_TRUE(inputs[0]->Name() == "attention_mask"); EXPECT_TRUE(inputs[1]->Name() == "Add_input_0"); // clean up - ASSERT_EQ(std::remove(context_binary_file.c_str()), 0); + CleanUpCtxFile(context_model_file); } TEST_F(QnnHTPBackendTests, QnnContextGenerationNodeNamePrefix) { @@ -519,20 +548,20 @@ TEST_F(QnnHTPBackendTests, QnnContextGenerationNodeNamePrefix) { auto& logging_manager = DefaultLoggingManager(); logging_manager.SetDefaultLoggerSeverity(logging::Severity::kERROR); - const std::string context_binary_file = "./qnn_ctx_2_inputs_order_test_gen.onnx"; + const std::string context_model_file = "./qnn_ctx_2_inputs_order_test_gen.onnx"; Ort::SessionOptions so; so.AddConfigEntry(kOrtSessionOptionEpContextEnable, "1"); - so.AddConfigEntry(kOrtSessionOptionEpContextFilePath, context_binary_file.c_str()); + so.AddConfigEntry(kOrtSessionOptionEpContextFilePath, context_model_file.c_str()); so.AddConfigEntry(kOrtSessionOptionEpContextNodeNamePrefix, node_name_prefix.c_str()); so.AppendExecutionProvider("QNN", provider_options); Ort::Session session(*ort_env, ORT_TSTR("testdata/qnn_ctx_2_inputs_order_test.onnx"), so); // Make sure the Qnn context cache binary file is generated - EXPECT_TRUE(std::filesystem::exists(context_binary_file.c_str())); + EXPECT_TRUE(std::filesystem::exists(context_model_file.c_str())); std::shared_ptr model; - ASSERT_STATUS_OK(Model::Load(ToPathString(context_binary_file), model, nullptr, DefaultLoggingManager().DefaultLogger())); + ASSERT_STATUS_OK(Model::Load(ToPathString(context_model_file), model, nullptr, DefaultLoggingManager().DefaultLogger())); for (auto& node : model->MainGraph().Nodes()) { if (node.OpType() == "EPContext") { EXPECT_TRUE(node.Name().find(node_name_prefix) != std::string::npos); @@ -540,7 +569,7 @@ TEST_F(QnnHTPBackendTests, QnnContextGenerationNodeNamePrefix) { } // clean up - ASSERT_EQ(std::remove(context_binary_file.c_str()), 0); + CleanUpCtxFile(context_model_file); } // Run QDQ model on HTP 3 times @@ -554,12 +583,12 @@ TEST_F(QnnHTPBackendTests, QnnContextBinaryCacheEmbedModeTest) { provider_options["backend_path"] = "libQnnHtp.so"; #endif provider_options["offload_graph_io_quantization"] = "0"; - const std::string context_binary_file = "./qnn_context_binary_test.onnx"; - std::remove(context_binary_file.c_str()); + const std::string context_model_file = "./qnn_context_binary_test.onnx"; + std::remove(context_model_file.c_str()); std::unordered_map session_option_pairs; session_option_pairs.emplace(kOrtSessionOptionEpContextEnable, "1"); - session_option_pairs.emplace(kOrtSessionOptionEpContextFilePath, context_binary_file); + session_option_pairs.emplace(kOrtSessionOptionEpContextFilePath, context_model_file); const TestInputDef input_def({1, 2, 3}, false, -10.0f, 10.0f); const std::string op_type = "Atan"; @@ -577,9 +606,11 @@ TEST_F(QnnHTPBackendTests, QnnContextBinaryCacheEmbedModeTest) { session_option_pairs); // Make sure the Qnn context cache binary file is generated - EXPECT_TRUE(std::filesystem::exists(context_binary_file.c_str())); + EXPECT_TRUE(std::filesystem::exists(context_model_file.c_str())); // 2nd run directly loads and run from Qnn context cache model + std::unordered_map session_option_pairs2; + session_option_pairs2.emplace(kOrtSessionOptionEpContextFilePath, context_model_file); TestQDQModelAccuracy(BuildOpTestCase(op_type, {input_def}, {}, {}), BuildQDQOpTestCase(op_type, {input_def}, {}, {}), provider_options, @@ -587,9 +618,10 @@ TEST_F(QnnHTPBackendTests, QnnContextBinaryCacheEmbedModeTest) { ExpectedEPNodeAssignment::All, QDQTolerance(), logging::Severity::kERROR, - context_binary_file); + context_model_file, + session_option_pairs2); // Clean up - ASSERT_EQ(std::remove(context_binary_file.c_str()), 0); + CleanUpCtxFile(context_model_file); } // Run QDQ model on HTP 3 times @@ -604,7 +636,7 @@ TEST_F(QnnHTPBackendTests, QnnContextBinaryCacheNonEmbedModeTest) { #endif provider_options["offload_graph_io_quantization"] = "0"; const std::string context_binary_file = "./testdata/qnn_context_cache_non_embed.onnx"; - std::string qnn_ctx_bin = "./testdata/qnn_context_cache_non_embed.onnx_QNNExecutionProvider_QNN_8283143575221199085_1_0.bin"; + std::string qnn_ctx_bin = "./testdata/qnn_context_cache_non_embed_QNN_8283143575221199085_1_0.bin"; std::unordered_map session_option_pairs; session_option_pairs.emplace(kOrtSessionOptionEpContextEnable, "1"); @@ -686,7 +718,7 @@ TEST_F(QnnHTPBackendTests, QnnContextBinaryCache_InvalidGraph) { #endif provider_options["offload_graph_io_quantization"] = "0"; const std::string context_binary_file = "./qnn_context_cache_non_embed.onnx"; - std::filesystem::path context_bin = "qnn_context_cache_non_embed.onnx_QNNExecutionProvider_QNN_8283143575221199085_1_0.bin"; + std::filesystem::path context_bin = "qnn_context_cache_non_embed_QNN_8283143575221199085_1_0.bin"; std::remove(context_binary_file.c_str()); std::remove(context_bin.string().c_str()); @@ -828,6 +860,7 @@ TEST_F(QnnHTPBackendTests, QnnContextBinaryFileNotExistTest) { SessionOptions so; so.session_logid = "qnn_ctx_model_logger"; + ASSERT_STATUS_OK(so.config_options.AddConfigEntry(kOrtSessionOptionEpContextFilePath, "./qnn_context_not_exist.onnx")); RunOptions run_options; run_options.run_tag = so.session_logid; @@ -841,7 +874,7 @@ TEST_F(QnnHTPBackendTests, QnnContextBinaryFileNotExistTest) { #endif provider_options["offload_graph_io_quantization"] = "0"; - ASSERT_STATUS_OK(session_object.RegisterExecutionProvider(QnnExecutionProviderWithOptions(provider_options))); + ASSERT_STATUS_OK(session_object.RegisterExecutionProvider(QnnExecutionProviderWithOptions(provider_options, &so))); ASSERT_STATUS_OK(session_object.Load(model_data.data(), static_cast(model_data.size()))); // Verify the return status with code INVALID_GRAPH ASSERT_TRUE(session_object.Initialize().Code() == common::StatusCode::INVALID_GRAPH); @@ -854,6 +887,7 @@ TEST_F(QnnHTPBackendTests, QnnContextBinaryFileEmptyStringTest) { SessionOptions so; so.session_logid = "qnn_ctx_model_logger"; + ASSERT_STATUS_OK(so.config_options.AddConfigEntry(kOrtSessionOptionEpContextFilePath, "./test_ctx.onnx")); RunOptions run_options; run_options.run_tag = so.session_logid; @@ -867,7 +901,7 @@ TEST_F(QnnHTPBackendTests, QnnContextBinaryFileEmptyStringTest) { #endif provider_options["offload_graph_io_quantization"] = "0"; - ASSERT_STATUS_OK(session_object.RegisterExecutionProvider(QnnExecutionProviderWithOptions(provider_options))); + ASSERT_STATUS_OK(session_object.RegisterExecutionProvider(QnnExecutionProviderWithOptions(provider_options, &so))); ASSERT_STATUS_OK(session_object.Load(model_data.data(), static_cast(model_data.size()))); // Verify the return status with code INVALID_GRAPH ASSERT_TRUE(session_object.Initialize().Code() == common::StatusCode::INVALID_GRAPH); @@ -884,12 +918,12 @@ TEST_F(QnnHTPBackendTests, QnnContextBinary2InputsTest) { provider_options["backend_path"] = "libQnnHtp.so"; #endif provider_options["offload_graph_io_quantization"] = "0"; - const std::string context_binary_file = "./qnn_context_binary_2inputs_test.onnx"; - std::remove(context_binary_file.c_str()); + const std::string context_model_file = "./qnn_context_binary_2inputs_test.onnx"; + std::remove(context_model_file.c_str()); std::unordered_map session_option_pairs; session_option_pairs.emplace(kOrtSessionOptionEpContextEnable, "1"); - session_option_pairs.emplace(kOrtSessionOptionEpContextFilePath, context_binary_file); + session_option_pairs.emplace(kOrtSessionOptionEpContextFilePath, context_model_file); const TestInputDef input_def1({1, 2, 3}, false, -10.0f, 10.0f); const TestInputDef input_def2({1, 2, 3}, false, -10.0f, 10.0f); @@ -908,9 +942,11 @@ TEST_F(QnnHTPBackendTests, QnnContextBinary2InputsTest) { session_option_pairs); // Make sure the Qnn context cache binary file is generated - EXPECT_TRUE(std::filesystem::exists(context_binary_file.c_str())); + EXPECT_TRUE(std::filesystem::exists(context_model_file.c_str())); // 2nd run directly loads and run from Qnn context cache model + std::unordered_map session_option_pairs2; + session_option_pairs2.emplace(kOrtSessionOptionEpContextFilePath, context_model_file); TestQDQModelAccuracy(BuildOpTestCase(op_type, {input_def1, input_def2}, {}, {}), BuildQDQOpTestCase(op_type, {input_def1, input_def2}, {}, {}), provider_options, @@ -918,9 +954,10 @@ TEST_F(QnnHTPBackendTests, QnnContextBinary2InputsTest) { ExpectedEPNodeAssignment::All, QDQTolerance(), logging::Severity::kERROR, - context_binary_file); + context_model_file, + session_option_pairs2); // Clean up - ASSERT_EQ(std::remove(context_binary_file.c_str()), 0); + CleanUpCtxFile(context_model_file); } // Context binary only contains a single QNN graph, generated context cache model (detached mode) only has 1 EPContext node @@ -936,14 +973,14 @@ TEST_F(QnnHTPBackendTests, QnnContextBinaryCache_SingleNodeNameNotMatchGraphName provider_options["backend_path"] = "libQnnHtp.so"; #endif provider_options["offload_graph_io_quantization"] = "0"; - const std::string context_binary_file = "./qnn_context_cache_non_embed.onnx"; - std::filesystem::path context_bin = "qnn_context_cache_non_embed.onnx_QNNExecutionProvider_QNN_8283143575221199085_1_0.bin"; - std::remove(context_binary_file.c_str()); + const std::string context_model_file = "./qnn_context_cache_non_embed.onnx"; + std::filesystem::path context_bin = "qnn_context_cache_non_embed_QNN_8283143575221199085_1_0.bin"; + std::remove(context_model_file.c_str()); std::remove(context_bin.string().c_str()); std::unordered_map session_option_pairs; session_option_pairs.emplace(kOrtSessionOptionEpContextEnable, "1"); - session_option_pairs.emplace(kOrtSessionOptionEpContextFilePath, context_binary_file); + session_option_pairs.emplace(kOrtSessionOptionEpContextFilePath, context_model_file); session_option_pairs.emplace(kOrtSessionOptionEpContextEmbedMode, "0"); const TestInputDef input_def({1, 2, 3}, false, -10.0f, 10.0f); @@ -962,7 +999,7 @@ TEST_F(QnnHTPBackendTests, QnnContextBinaryCache_SingleNodeNameNotMatchGraphName session_option_pairs); // Check the Onnx skeleton file is generated - EXPECT_TRUE(std::filesystem::exists(context_binary_file.c_str())); + EXPECT_TRUE(std::filesystem::exists(context_model_file.c_str())); // Check the Qnn context cache binary file is generated EXPECT_TRUE(std::filesystem::exists(context_bin)); @@ -990,18 +1027,19 @@ TEST_F(QnnHTPBackendTests, QnnContextBinaryCache_SingleNodeNameNotMatchGraphName SessionOptions so; so.session_logid = "qnn_ctx_model_logger"; + ASSERT_STATUS_OK(so.config_options.AddConfigEntry(kOrtSessionOptionEpContextFilePath, context_model_file.c_str())); RunOptions run_options; run_options.run_tag = so.session_logid; InferenceSessionWrapper session_object{so, GetEnvironment()}; - ASSERT_STATUS_OK(session_object.RegisterExecutionProvider(QnnExecutionProviderWithOptions(provider_options))); + ASSERT_STATUS_OK(session_object.RegisterExecutionProvider(QnnExecutionProviderWithOptions(provider_options, &so))); ASSERT_STATUS_OK(session_object.Load(model_data.data(), static_cast(model_data.size()))); // Verify the return status with code INVALID_GRAPH ASSERT_TRUE(session_object.Initialize().Code() == common::StatusCode::OK); // Clean up - ASSERT_EQ(std::remove(context_binary_file.c_str()), 0); + ASSERT_EQ(std::remove(context_model_file.c_str()), 0); ASSERT_EQ(std::remove(context_bin.string().c_str()), 0); } @@ -1050,80 +1088,33 @@ static void CreateQdqModel(const std::string& model_file_name, const Logger& log ASSERT_STATUS_OK(onnxruntime::Model::Save(model, ToPathString(model_file_name))); } -static void DumpModelWithSharedCtx(const ProviderOptions& provider_options, +static void DumpModelWithSharedCtx(ProviderOptions provider_options, const std::string& onnx_model_path1, const std::string& onnx_model_path2) { - SessionOptions so; - so.session_logid = "qnn_ctx_model_logger"; - ASSERT_STATUS_OK(so.config_options.AddConfigEntry(kOrtSessionOptionEpContextEnable, "1")); - ASSERT_STATUS_OK(so.config_options.AddConfigEntry(kOrtSessionOptionEpContextEmbedMode, "0")); - RunOptions run_options; - run_options.run_tag = so.session_logid; - - auto qnn_ep = QnnExecutionProviderWithOptions(provider_options, &so); - std::shared_ptr qnn_ep_shared(std::move(qnn_ep)); + Ort::SessionOptions so; + so.AddConfigEntry(kOrtSessionOptionEpContextEnable, "1"); + so.AddConfigEntry(kOrtSessionOptionEpContextEmbedMode, "0"); + // enable ep.share_ep_contexts so that QNNEP share the QnnBackendManager across sessions + so.AddConfigEntry(kOrtSessionOptionShareEpContexts, "1"); - InferenceSessionWrapper session_object1{so, GetEnvironment()}; - ASSERT_STATUS_OK(session_object1.RegisterExecutionProvider(qnn_ep_shared)); - ASSERT_STATUS_OK(session_object1.Load(ToPathString(onnx_model_path1))); - ASSERT_STATUS_OK(session_object1.Initialize()); +#ifndef __aarch64__ +#ifndef _M_ARM64 + // weight sharing only available for v73 and higher + provider_options["soc_model"] = "60"; +#endif // !_M_ARM64 +#endif // !__aarch64__ - InferenceSessionWrapper session_object2{so, GetEnvironment()}; - ASSERT_STATUS_OK(session_object2.RegisterExecutionProvider(qnn_ep_shared)); - ASSERT_STATUS_OK(session_object2.Load(ToPathString(onnx_model_path2))); - ASSERT_STATUS_OK(session_object2.Initialize()); -} + so.AppendExecutionProvider("QNN", provider_options); -// from the last context ache Onnx model, find the EPContext node with main_context=1, -// and get the QNN context binary file name, thie context binary contains all graphs from all Onnx models -static void GetLastContextBinaryFileName(const std::string last_onnx_ctx_file, - std::string& last_ctx_bin_file, - const Logger& logger) { - std::shared_ptr ctx_model; - ASSERT_STATUS_OK(Model::Load(ToPathString(last_onnx_ctx_file), ctx_model, nullptr, logger)); - auto& ctx_graph = ctx_model->MainGraph(); - for (auto& node : ctx_graph.Nodes()) { - if (node.OpType() == "EPContext") { - int64_t is_main_context = GetNodeAttr(node, "main_context", static_cast(0)); - if (1 == is_main_context) { - last_ctx_bin_file = GetNodeAttr(node, "ep_cache_context", ""); - return; - } - } - } -} + // Create 2 sessions to generate context binary models, the 1st session will share the QnnBackendManager + // to the 2nd session, so graphs from these 2 models are all included in the 2nd context binary + Ort::Session session1(*ort_env, ToPathString(onnx_model_path1).c_str(), so); -// Update generated context cache Onnx model to make the main EPContext node point to -// the last QNN context binary file -// Remove not used QNN context binary file, only keep the last one which contains all graphs -static void UpdateEpContextModel(const std::vector& ep_ctx_files, - const std::string& last_qnn_ctx_binary_file_name, - const Logger& logger) { - for (auto ep_ctx_file : ep_ctx_files) { - std::shared_ptr ctx_model; - auto path_str = ToPathString(ep_ctx_file); - ASSERT_STATUS_OK(Model::Load(path_str, ctx_model, nullptr, logger)); - auto& ctx_graph = ctx_model->MainGraph(); - GraphViewer graph_viewer(ctx_graph); - auto path = std::filesystem::path(path_str); - - for (auto& node : ctx_graph.Nodes()) { - if (node.OpType() == "EPContext") { - int64_t is_main_context = GetNodeAttr(node, "main_context", static_cast(0)); - if (1 == is_main_context) { - std::string old_qnn_ctx_binary_file_name = GetNodeAttr(node, "ep_cache_context", ""); - auto file_path = path.replace_filename(old_qnn_ctx_binary_file_name); - std::remove(file_path.string().c_str()); - node.ClearAttribute("ep_cache_context"); - node.AddAttribute("ep_cache_context", last_qnn_ctx_binary_file_name); - } - } - } - std::remove(ep_ctx_file.c_str()); - ASSERT_STATUS_OK(Model::Save(*ctx_model.get(), ToPathString(ep_ctx_file))); - } + so.AddConfigEntry(kOrtSessionOptionStopShareEpContexts, "1"); + Ort::Session session2(*ort_env, ToPathString(onnx_model_path2).c_str(), so); } +#if defined(__aarch64__) || defined(_M_ARM64) static void GetModelInputNames(const std::string& model_path, std::vector& input_names, std::vector& output_names, @@ -1143,16 +1134,16 @@ static void GetModelInputNames(const std::string& model_path, output_names.push_back(output->Name()); } } +#endif // 1. Create 2 QDQ models // 2. Initialize 2 Ort sessions which share the same QNN EP from these 2 QDQ models // with EpContextEnable = 1, to dump the context binary // so, the 2nd context binary contains the graph from the 1st model -// 3. Change the 1st context model to point to the 2nd context binary file -// 4. Start 2 ort session from the dumped context model, +// 3. Start 2 ort session from the dumped context model, // The 2nd session uses graph from 1st session -// 5. Run the 2nd session -TEST_F(QnnHTPBackendTests, QnnContextShareAcrossSessions1) { +// 4. Run the 2nd session +TEST_F(QnnHTPBackendTests, QnnContextShareAcrossSessions) { ProviderOptions provider_options; #if defined(_WIN32) provider_options["backend_path"] = "QnnHtp.dll"; @@ -1163,29 +1154,45 @@ TEST_F(QnnHTPBackendTests, QnnContextShareAcrossSessions1) { // Create QDQ models std::vector onnx_model_paths{"./weight_share1.onnx", "./weight_share2.onnx"}; + // cleanup in case some failure test doesn't remove them + for (auto model_path : onnx_model_paths) { + std::remove(model_path.c_str()); + } + std::vector ctx_model_paths; for (auto model_path : onnx_model_paths) { CreateQdqModel(model_path, DefaultLoggingManager().DefaultLogger()); EXPECT_TRUE(std::filesystem::exists(model_path.c_str())); - ctx_model_paths.push_back(model_path + "_ctx.onnx"); + auto pos = model_path.find_last_of("."); + if (pos != std::string::npos) { + model_path = model_path.substr(0, pos) + "_ctx.onnx"; + } else { + model_path = model_path + "_ctx.onnx"; + } + ctx_model_paths.push_back(model_path); + } + for (auto ctx_model_path : ctx_model_paths) { + std::remove(ctx_model_path.c_str()); } DumpModelWithSharedCtx(provider_options, onnx_model_paths[0], onnx_model_paths[1]); - // Get the last context binary file name - std::string last_qnn_ctx_binary_file_name; - GetLastContextBinaryFileName(ctx_model_paths.back(), last_qnn_ctx_binary_file_name, - DefaultLoggingManager().DefaultLogger()); - EXPECT_TRUE(!last_qnn_ctx_binary_file_name.empty()); - - // Update generated context cache Onnx model to make the main EPContext node point to - // the last QNN context binary file - // Remove not used QNN context binary file, only keep the last one which contains all graphs - std::vector ctx_model_paths_to_update(ctx_model_paths); - ctx_model_paths_to_update.pop_back(); - UpdateEpContextModel(ctx_model_paths_to_update, last_qnn_ctx_binary_file_name, - DefaultLoggingManager().DefaultLogger()); - + std::string qnn_ctx_binary_file_name1; + GetContextBinaryFileName(ctx_model_paths[0], qnn_ctx_binary_file_name1, + DefaultLoggingManager().DefaultLogger()); + EXPECT_TRUE(!qnn_ctx_binary_file_name1.empty()); + + std::string qnn_ctx_binary_file_name2; + GetContextBinaryFileName(ctx_model_paths[1], qnn_ctx_binary_file_name2, + DefaultLoggingManager().DefaultLogger()); + EXPECT_TRUE(!qnn_ctx_binary_file_name2.empty()); + // 2 *_ctx.onn point to same .bin file + EXPECT_TRUE(qnn_ctx_binary_file_name1 == qnn_ctx_binary_file_name2); + auto file_size_1 = std::filesystem::file_size(qnn_ctx_binary_file_name1); + EXPECT_TRUE(file_size_1 > 0); + + // only load and run the session on real device +#if defined(__aarch64__) || defined(_M_ARM64) Ort::SessionOptions so1; so1.SetLogId("so1"); so1.AddConfigEntry(kOrtSessionOptionShareEpContexts, "1"); @@ -1231,6 +1238,7 @@ TEST_F(QnnHTPBackendTests, QnnContextShareAcrossSessions1) { auto ort_outputs1 = session1.Run(Ort::RunOptions{}, input_names_c.data(), ort_inputs.data(), ort_inputs.size(), output_names_c.data(), 1); +#endif for (auto model_path : onnx_model_paths) { std::remove(model_path.c_str()); @@ -1238,19 +1246,12 @@ TEST_F(QnnHTPBackendTests, QnnContextShareAcrossSessions1) { for (auto ctx_model_path : ctx_model_paths) { std::remove(ctx_model_path.c_str()); } - std::remove(last_qnn_ctx_binary_file_name.c_str()); + std::remove(qnn_ctx_binary_file_name1.c_str()); } -// 1. Create 2 QDQ models -// 2. Initialize 2 Ort sessions which share the same QNN EP from these 2 QDQ models -// with EpContextEnable = 1, to dump the context binary -// so, the 2nd context binary contains the graph from the 1st model -// 3. Change the 1st context model to point to a context binary file which is not exist -// 4. Start 2 ort session from the dumped context model, -// The 1st session uses the 2nd model, the 2nd session uses the 1st model -// so the 2nd session uses graph from the 1st session -// 6. Run the 2nd session -TEST_F(QnnHTPBackendTests, QnnContextShareAcrossSessions2) { +// For Ort sessions to generate the context binary, with session option ep.share_ep_contexts enabled +// Ort sessions will share the QnnBackendManager, so that all graphs from all models compile into the same Qnn context +TEST_F(QnnHTPBackendTests, QnnContextGenWeightSharingSessionAPI) { ProviderOptions provider_options; #if defined(_WIN32) provider_options["backend_path"] = "QnnHtp.dll"; @@ -1260,81 +1261,53 @@ TEST_F(QnnHTPBackendTests, QnnContextShareAcrossSessions2) { provider_options["offload_graph_io_quantization"] = "0"; // Create QDQ models - std::vector onnx_model_paths{"./weight_share21.onnx", "./weight_share22.onnx"}; + std::vector onnx_model_paths{"./weight_share1.onnx", "./weight_share2.onnx"}; + // cleanup in case some failure test doesn't remove them + for (auto model_path : onnx_model_paths) { + std::remove(model_path.c_str()); + } + std::vector ctx_model_paths; for (auto model_path : onnx_model_paths) { CreateQdqModel(model_path, DefaultLoggingManager().DefaultLogger()); EXPECT_TRUE(std::filesystem::exists(model_path.c_str())); - ctx_model_paths.push_back(model_path + "_ctx.onnx"); + auto pos = model_path.find_last_of("."); + if (pos != std::string::npos) { + model_path = model_path.substr(0, pos) + "_ctx.onnx"; + } else { + model_path = model_path + "_ctx.onnx"; + } + ctx_model_paths.push_back(model_path); + } + for (auto ctx_model_path : ctx_model_paths) { + std::remove(ctx_model_path.c_str()); } DumpModelWithSharedCtx(provider_options, onnx_model_paths[0], onnx_model_paths[1]); - // Get the last context binary file name - std::string last_qnn_ctx_binary_file_name; - GetLastContextBinaryFileName(ctx_model_paths.back(), last_qnn_ctx_binary_file_name, - DefaultLoggingManager().DefaultLogger()); - EXPECT_TRUE(!last_qnn_ctx_binary_file_name.empty()); - - // Update generated context cache Onnx model to make the main EPContext node point to - // the last QNN context binary file - // Remove not used QNN context binary file, only keep the last one which contains all graphs - std::vector ctx_model_paths_to_update(ctx_model_paths); - ctx_model_paths_to_update.pop_back(); - // The 2nd model still point to the context binary which includes all graphs - // The 1st model point to file not exists - UpdateEpContextModel(ctx_model_paths_to_update, "file_not_exist.bin", - DefaultLoggingManager().DefaultLogger()); + std::string qnn_ctx_binary_file_name1; + GetContextBinaryFileName(ctx_model_paths[0], qnn_ctx_binary_file_name1, + DefaultLoggingManager().DefaultLogger()); + EXPECT_TRUE(!qnn_ctx_binary_file_name1.empty()); - Ort::SessionOptions so; - so.AddConfigEntry(kOrtSessionOptionShareEpContexts, "1"); - so.AppendExecutionProvider("QNN", provider_options); + std::string qnn_ctx_binary_file_name2; + GetContextBinaryFileName(ctx_model_paths[1], qnn_ctx_binary_file_name2, + DefaultLoggingManager().DefaultLogger()); + EXPECT_TRUE(!qnn_ctx_binary_file_name2.empty()); - EXPECT_TRUE(2 == ctx_model_paths.size()); -#ifdef _WIN32 - std::wstring ctx_model_file1(ctx_model_paths[0].begin(), ctx_model_paths[0].end()); - std::wstring ctx_model_file2(ctx_model_paths[1].begin(), ctx_model_paths[1].end()); -#else - std::string ctx_model_file1(ctx_model_paths[0].begin(), ctx_model_paths[0].end()); - std::string ctx_model_file2(ctx_model_paths[1].begin(), ctx_model_paths[1].end()); -#endif - // Create session from the 2nd model first - Ort::Session session1(*ort_env, ctx_model_file2.c_str(), so); - Ort::Session session2(*ort_env, ctx_model_file1.c_str(), so); - - std::vector input_names; - std::vector output_names; - GetModelInputNames(ctx_model_paths[1], input_names, output_names, - DefaultLoggingManager().DefaultLogger()); - - // Run sessions - // prepare input - std::vector input_dim{2, 3}; - std::vector input_value(2 * 3, 0.0f); - Ort::MemoryInfo info("Cpu", OrtDeviceAllocator, 0, OrtMemTypeDefault); - std::vector ort_inputs; - std::vector input_names_c; - for (size_t i = 0; i < input_names.size(); ++i) { - auto input_tensor = Ort::Value::CreateTensor(info, input_value.data(), input_value.size(), - input_dim.data(), input_dim.size()); - ort_inputs.push_back(std::move(input_tensor)); - input_names_c.push_back(input_names[i].c_str()); - } - std::vector output_names_c; - for (size_t i = 0; i < output_names.size(); ++i) { - output_names_c.push_back(output_names[i].c_str()); - } - - auto ort_outputs1 = session1.Run(Ort::RunOptions{}, input_names_c.data(), ort_inputs.data(), ort_inputs.size(), - output_names_c.data(), 1); + // 2 *_ctx.onn point to same .bin file + EXPECT_TRUE(qnn_ctx_binary_file_name1 == qnn_ctx_binary_file_name2); + auto file_size_1 = std::filesystem::file_size(qnn_ctx_binary_file_name1); + EXPECT_TRUE(file_size_1 > 0); + // clean up for (auto model_path : onnx_model_paths) { - std::remove(model_path.c_str()); + ASSERT_EQ(std::remove(model_path.c_str()), 0); } for (auto ctx_model_path : ctx_model_paths) { - std::remove(ctx_model_path.c_str()); + ASSERT_EQ(std::remove(ctx_model_path.c_str()), 0); } - std::remove(last_qnn_ctx_binary_file_name.c_str()); + ASSERT_EQ(std::remove(qnn_ctx_binary_file_name1.c_str()), 0); } #endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) diff --git a/onnxruntime/test/providers/qnn/qnn_test_utils.cc b/onnxruntime/test/providers/qnn/qnn_test_utils.cc index e2deccc4fff0f..6f8a7a9ecb602 100644 --- a/onnxruntime/test/providers/qnn/qnn_test_utils.cc +++ b/onnxruntime/test/providers/qnn/qnn_test_utils.cc @@ -14,6 +14,7 @@ #include "core/framework/compute_capability.h" #include "core/graph/graph.h" #include "core/session/onnxruntime_session_options_config_keys.h" +#include "core/optimizer/graph_optimizer_registry.h" namespace onnxruntime { namespace test { @@ -278,10 +279,11 @@ static BackendSupport GetHTPSupport(const onnxruntime::logging::Logger& logger) MockKernelLookup kernel_lookup; onnxruntime::GraphViewer graph_viewer(graph); std::unique_ptr qnn_ep = QnnExecutionProviderWithOptions( - {{"backend_path", "QnnHtp.dll"}, {"offload_graph_io_quantization", "0"}}); + {{"backend_type", "htp"}, {"offload_graph_io_quantization", "0"}}); + GraphOptimizerRegistry graph_optimizer_registry(nullptr, nullptr, nullptr); // as a placeholder to feed into GetCapability qnn_ep->SetLogger(&logger); - auto result = qnn_ep->GetCapability(graph_viewer, kernel_lookup, nullptr); + auto result = qnn_ep->GetCapability(graph_viewer, kernel_lookup, graph_optimizer_registry, nullptr); return result.empty() ? BackendSupport::UNSUPPORTED : BackendSupport::SUPPORTED; } @@ -341,10 +343,11 @@ static BackendSupport GetCPUSupport(const onnxruntime::logging::Logger& logger) MockKernelLookup kernel_lookup; onnxruntime::GraphViewer graph_viewer(graph); std::unique_ptr qnn_ep = QnnExecutionProviderWithOptions( - {{"backend_path", "QnnCpu.dll"}, {"offload_graph_io_quantization", "0"}}); + {{"backend_type", "cpu"}, {"offload_graph_io_quantization", "0"}}); + GraphOptimizerRegistry graph_optimizer_registry(nullptr, nullptr, nullptr); // as a placeholder to feed into GetCapability qnn_ep->SetLogger(&logger); - auto result = qnn_ep->GetCapability(graph_viewer, kernel_lookup, nullptr); + auto result = qnn_ep->GetCapability(graph_viewer, kernel_lookup, graph_optimizer_registry, nullptr); return result.empty() ? BackendSupport::UNSUPPORTED : BackendSupport::SUPPORTED; } diff --git a/onnxruntime/test/providers/qnn/reduce_op_test.cc b/onnxruntime/test/providers/qnn/reduce_op_test.cc index 290630c1254f9..f96e5338369b2 100644 --- a/onnxruntime/test/providers/qnn/reduce_op_test.cc +++ b/onnxruntime/test/providers/qnn/reduce_op_test.cc @@ -84,18 +84,10 @@ static void RunReduceTest(const std::string& op_type, ProviderOptions provider_options; provider_options["offload_graph_io_quantization"] = "0"; if (enable_fp16) { -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["enable_htp_fp16_precision"] = "1"; } else { -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif + provider_options["backend_type"] = "cpu"; } RunQnnModelTest(BuildReduceOpTestCase(op_type, @@ -419,11 +411,7 @@ static void RunReduceOpQDQTest(const std::string& op_type, int opset, ExpectedEPNodeAssignment expected_ep_assignment) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; constexpr bool noop_with_empty_axes = false; diff --git a/onnxruntime/test/providers/qnn/reshape_expand_op_test.cc b/onnxruntime/test/providers/qnn/reshape_expand_op_test.cc index ea55cb46099bb..b978e3a0790db 100644 --- a/onnxruntime/test/providers/qnn/reshape_expand_op_test.cc +++ b/onnxruntime/test/providers/qnn/reshape_expand_op_test.cc @@ -25,11 +25,7 @@ static void RunReshapeExpandTestOnCPU(const std::string& op_type, int opset = 19) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif + provider_options["backend_type"] = "cpu"; provider_options["offload_graph_io_quantization"] = "0"; RunQnnModelTest(BuildOpTestCase(op_type, {input_def}, {shape_def}, attrs), @@ -157,11 +153,7 @@ static void RunReshapeExpandTestOnHTP(const std::string& op_type, int opset = 19) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; RunQnnModelTest(BuildOpTestCase(op_type, {input_def}, {shape_def}, attrs), @@ -182,11 +174,7 @@ static void RunQDQReshapeExpandTestOnHTP(const std::string& op_type, bool use_contrib_qdq = false) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; auto f32_model_builder = BuildOpTestCase(op_type, {input_def}, {shape_def}, attrs); diff --git a/onnxruntime/test/providers/qnn/resize_test.cc b/onnxruntime/test/providers/qnn/resize_test.cc index f323713d6082d..fbd729fa998d9 100644 --- a/onnxruntime/test/providers/qnn/resize_test.cc +++ b/onnxruntime/test/providers/qnn/resize_test.cc @@ -122,11 +122,7 @@ static void RunCPUResizeOpTest(const TestInputDef& input_def, const std:: ExpectedEPNodeAssignment expected_ep_assignment, int opset = 19) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif + provider_options["backend_type"] = "cpu"; provider_options["offload_graph_io_quantization"] = "0"; RunQnnModelTest(GetResizeModelBuilder(input_def, sizes_data, mode, coordinate_transformation_mode, nearest_mode), @@ -141,11 +137,7 @@ static void RunCPUResizeOpTestWithScales(const TestInputDef& input_def, c ExpectedEPNodeAssignment expected_ep_assignment, int opset = 19) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif + provider_options["backend_type"] = "cpu"; provider_options["offload_graph_io_quantization"] = "0"; RunQnnModelTest(GetResizeModelBuilderWithScales(input_def, scales_data, mode, coordinate_transformation_mode, nearest_mode), @@ -163,11 +155,7 @@ static void RunQDQResizeOpTest(const TestInputDef& input_def, int opset = 19, QDQTolerance tolerance = QDQTolerance()) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; TestQDQModelAccuracy(GetResizeModelBuilder(input_def, sizes_data, mode, coordinate_transformation_mode, nearest_mode), @@ -271,14 +259,20 @@ TEST_F(QnnCPUBackendTests, ResizeDownsampleNearestAlignCorners_rpf) { // Cpu tests that use the "linear" mode. // -TEST_F(QnnCPUBackendTests, Resize2xLinearHalfPixel) { +// accuracy issue since QNN 2.31 +// Expected: contains 240 values, where each value and its corresponding value in 16-byte object are an almost-equal pair +// Actual: 16-byte object , where the value pair (-10, -10.5084743) at index #0 don't match, which is -0.508474 from -10 +TEST_F(QnnCPUBackendTests, DISABLED_Resize2xLinearHalfPixel) { std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 60); RunCPUResizeOpTest(TestInputDef({1, 3, 4, 5}, false, input_data), {1, 3, 8, 10}, "linear", "half_pixel", "", ExpectedEPNodeAssignment::All); } -TEST_F(QnnCPUBackendTests, Resize2xLinearHalfPixel_scales) { +// accuracy issue since QNN 2.31 +// Expected: contains 240 values, where each value and its corresponding value in 16-byte object are an almost-equal pair +// Actual: 16-byte object , where the value pair (-10, -10.5084743) at index #0 don't match, which is -0.508474 from -10 +TEST_F(QnnCPUBackendTests, DISABLED_Resize2xLinearHalfPixel_scales) { std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 60); RunCPUResizeOpTestWithScales(TestInputDef({1, 3, 4, 5}, false, input_data), {1.0f, 1.0f, 2.0f, 2.0f}, "linear", "half_pixel", "", @@ -456,11 +450,12 @@ TEST_F(QnnHTPBackendTests, ResizeU8_2xNearestAsymmetricRoundPreferFloor_Unsuppor // ORT CPU EP (f32 model) outputs: -10.0000000 -10.0000000 -3.33333349 -3.33333349 -3.33333349 -3.33333349 -10.00 ... // ORT CPU EP (qdq model) outputs: -9.96078491 -9.96078491 -3.29411769 -3.29411769 -3.29411769 -3.29411769 -9.961 ... // ORT QNN EP (qdq model) outputs: -9.96078491 -9.96078491 -9.96078491 -3.37254906 -3.37254906 -3.37254906 -9.961 ... -TEST_F(QnnHTPBackendTests, DISABLED_ResizeU8_3xNearestAsymmetricRoundPreferFloor) { +// UPDATE: "round_prefer_floor" no longer supported in QNN SDK 2.21 (supported in QNN SDK 2.19) +TEST_F(QnnHTPBackendTests, ResizeU8_3xNearestAsymmetricRoundPreferFloor_Unsupported) { std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 4); RunQDQResizeOpTest(TestInputDef({1, 1, 2, 2}, false, input_data), {1, 1, 6, 6}, "nearest", "asymmetric", "round_prefer_floor", - ExpectedEPNodeAssignment::All); + ExpectedEPNodeAssignment::None); // No longer supported as of QNN SDK 2.21 } // Test 0.5x QDQ Resize mode: "nearest", coordinate_transformation_mode: "asymmetric", nearest_mode: "floor" diff --git a/onnxruntime/test/providers/qnn/simple_op_htp_test.cc b/onnxruntime/test/providers/qnn/simple_op_htp_test.cc index 3a557c5708900..0eec5f800916f 100644 --- a/onnxruntime/test/providers/qnn/simple_op_htp_test.cc +++ b/onnxruntime/test/providers/qnn/simple_op_htp_test.cc @@ -27,11 +27,7 @@ static void RunOpTestOnCPU(const std::string& op_type, ExpectedEPNodeAssignment expected_ep_assignment, const std::string& op_domain = kOnnxDomain) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif + provider_options["backend_type"] = "cpu"; provider_options["offload_graph_io_quantization"] = "0"; RunQnnModelTest(BuildOpTestCase(op_type, input_defs, {}, attrs, op_domain), @@ -49,7 +45,8 @@ static void RunOpTestOnCPU(const std::string& op_type, // index #2 don't match, which is -1.9 from 2 // // If/when fixed, enable QNN EP in cpu test TensorOpTest.SpaceToDepthTest_1 -TEST_F(QnnCPUBackendTests, DISABLED_SpaceToDepth_Flaky) { +// fixed by QNN 2.32 +TEST_F(QnnCPUBackendTests, SpaceToDepth_Flaky) { std::vector X = {0.0f, 0.1f, 0.2f, 0.3f, 1.0f, 1.1f, 1.2f, 1.3f, @@ -73,7 +70,8 @@ TEST_F(QnnCPUBackendTests, DISABLED_SpaceToDepth_Flaky) { // at index #2 don't match, which is -17 from 18 // // If/when fixed, enable QNN EP in cpu test TensorOpTest.SpaceToDepthTest_2 -TEST_F(QnnCPUBackendTests, DISABLED_SpaceToDepth_Flaky2) { +// fixed by QNN 2.32 +TEST_F(QnnCPUBackendTests, SpaceToDepth_Flaky2) { const std::vector X = { 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., 17., 18., 19., 20., 21., @@ -125,11 +123,7 @@ static void RunQDQOpTest(const std::string& op_type, bool use_contrib_qdq = false, QDQTolerance tolerance = QDQTolerance()) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; TestQDQModelAccuracy(BuildOpTestCase(op_type, input_defs, {}, attrs, op_domain), @@ -151,11 +145,7 @@ static void RunOpTest(const std::string& op_type, float fp32_abs_err = 1e-5f, bool enable_htp_fp16_precision = false) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; if (enable_htp_fp16_precision) { provider_options["enable_htp_fp16_precision"] = "1"; @@ -178,11 +168,7 @@ static void RunFP16OpTest(const std::string& op_type, const std::string& op_domain = kOnnxDomain, float tolerance = 0.004f) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; std::vector> input_fp16_defs; input_fp16_defs.reserve(input_defs.size()); @@ -297,7 +283,8 @@ TEST_F(QnnHTPBackendTests, UnaryOp_Elu) { // Expected val: -0.99751651287078857 // QNN QDQ val: 6.2726154327392578 (err 7.2701320648193359) // CPU QDQ val: -0.99753034114837646 (err 1.3828277587890625e-05) -TEST_F(QnnHTPBackendTests, DISABLE_UnaryOp_Elu_U16) { +// Issue fixed in 2.30 +TEST_F(QnnHTPBackendTests, UnaryOp_Elu_U16) { RunQDQOpTest("Elu", {TestInputDef({1, 2, 3}, false, GetFloatDataInRange(-10.0f, 10.0f, 6))}, {}, @@ -568,18 +555,18 @@ TEST_F(QnnHTPBackendTests, UnaryOp_Softmax13_U16_NonLastAxis_LargeInput) { } // Check that QNN compiles DQ -> Softmax -> Q as a single unit. -// Test that the default axis (1) for SoftMax opset < 13 does not work. -TEST_F(QnnHTPBackendTests, UnaryOp_Softmax11_DefaultAxisFails) { +// Test that the default axis (1) for SoftMax opset < 13 works. +TEST_F(QnnHTPBackendTests, UnaryOp_Softmax11_DefaultAxis) { RunQDQOpTest("Softmax", {TestInputDef({1, 2, 3}, false, -5.0f, 5.0f)}, {}, // Uses default axis of 1 for opset < 13. 11, - ExpectedEPNodeAssignment::None); + ExpectedEPNodeAssignment::All); } // Check that QNN compiles DQ -> Softmax -> Q as a single unit. // Test that setting an axis value of -1 works for Softmax opset < 13. -TEST_F(QnnHTPBackendTests, UnaryOp_Softmax11_SetValidAxis) { +TEST_F(QnnHTPBackendTests, UnaryOp_Softmax11_SetAxis) { RunQDQOpTest("Softmax", {TestInputDef({1, 2, 3}, false, -5.0f, 5.0f)}, {utils::MakeAttribute("axis", static_cast(-1))}, @@ -610,19 +597,19 @@ TEST_F(QnnHTPBackendTests, UnaryOp_LogSoftmax13_NonLastAxis) { } // Check that QNN compiles DQ -> LogSoftmax -> Q as a single unit. -// Test that the default axis (1) for LogSoftmax opset < 13 does not work. -TEST_F(QnnHTPBackendTests, UnaryOp_LogSoftmax11_DefaultAxisFails) { +// Test that the default axis (1) for LogSoftmax opset < 13 works. +TEST_F(QnnHTPBackendTests, UnaryOp_LogSoftmax11_DefaultAxis) { std::vector input_data = GetFloatDataInRange(-5.0f, 5.0f, 6); RunQDQOpTest("LogSoftmax", {TestInputDef({1, 2, 3}, false, input_data)}, {}, // Uses default axis of 1 for opset < 13. 11, - ExpectedEPNodeAssignment::None); + ExpectedEPNodeAssignment::All); } // Check that QNN compiles DQ -> LogSoftmax -> Q as a single unit. // Test that setting an axis value of -1 works for LogSoftmax opset < 13. -TEST_F(QnnHTPBackendTests, UnaryOp_LogSoftmax11_SetValidAxis) { +TEST_F(QnnHTPBackendTests, UnaryOp_LogSoftmax11_SetAxis) { std::vector input_data = GetFloatDataInRange(-5.0f, 5.0f, 6); RunQDQOpTest("LogSoftmax", {TestInputDef({1, 2, 3}, false, input_data)}, @@ -780,11 +767,7 @@ TEST_F(QnnHTPBackendTests, SpaceToDepthOp_U16) { TEST_F(QnnHTPBackendTests, QuantAccuracyTest) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; // Note: a graph input -> Q -> DQ -> is optimized by Qnn to have a perfectly accurate output. @@ -1053,7 +1036,10 @@ TEST_F(QnnHTPBackendTests, GridSample_AlignCorners) { utils::MakeAttribute("mode", "bilinear"), utils::MakeAttribute("padding_mode", "zeros")}, 17, - ExpectedEPNodeAssignment::All); + ExpectedEPNodeAssignment::All, + kOnnxDomain, + false, + QDQTolerance(0.008f)); } // Test 16-bit QDQ GridSample with align corners @@ -1115,7 +1101,8 @@ TEST_F(QnnHTPBackendTests, GridSample_U16_Nearest) { // Expected val: 3.212885856628418 // QNN QDQ val: 3.1308119297027588 (err 0.08207392692565918) // CPU QDQ val: 3.2036216259002686 (err 0.0092642307281494141) -TEST_F(QnnHTPBackendTests, DISABLED_GridSample_ReflectionPaddingMode) { +// fixed by QNN 2.32 +TEST_F(QnnHTPBackendTests, GridSample_ReflectionPaddingMode) { RunQDQOpTest("GridSample", {TestInputDef({1, 1, 3, 2}, false, -10.0f, 10.0f), TestInputDef({1, 2, 4, 2}, false, -10.0f, 10.0f)}, @@ -1208,11 +1195,7 @@ TEST_F(QnnHTPBackendTests, Add_U8_U16_Convert) { TestInputDef input1_def({1, 2, 2, 2}, false, input1_data); ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; TestQDQModelAccuracy(BuildOpTestCase("Add", {input0_def, input1_def}, {}, {}, kOnnxDomain), @@ -1274,11 +1257,7 @@ TEST_F(QnnHTPBackendTests, DQ_Q_ConvertFusion_SameType) { TestInputDef input1_def({1, 2, 2, 2}, false, input1_data); ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; QuantParams out_qparams_u8 = {1.0f, 128}; @@ -1405,11 +1384,7 @@ static GetTestModelFn BuildHardSigmoidFusionTestCase(TestInputDef& in TEST_F(QnnHTPBackendTests, HardSigmoidFusedIntoHardSwish_FP32_as_FP16) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["enable_htp_fp16_precision"] = "1"; @@ -1432,11 +1407,7 @@ TEST_F(QnnHTPBackendTests, HardSigmoidFusedIntoHardSwish_FP32_as_FP16) { TEST_F(QnnHTPBackendTests, HardSigmoidFusedIntoHardSwish_FP16) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; std::vector input_data = {-8.0f, -2.0f, 0.0f, 0.5f, 0.9f, 1.1f, 3.3f, 8.0f, -7.0f, 0.0f, 0.2f, 0.4f, 0.8f, 2.1f, 4.3f, 7.0f}; diff --git a/onnxruntime/test/providers/qnn/slice_htp_test.cc b/onnxruntime/test/providers/qnn/slice_htp_test.cc index dc16192188e0b..9c50f47d462bc 100644 --- a/onnxruntime/test/providers/qnn/slice_htp_test.cc +++ b/onnxruntime/test/providers/qnn/slice_htp_test.cc @@ -44,11 +44,7 @@ TEST_F(QnnCPUBackendTests, Slice_SharedInitializersBugFix) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif + provider_options["backend_type"] = "cpu"; RunQnnModelTest(model_fn, provider_options, @@ -79,11 +75,7 @@ static void RunSliceQDQTest(const TestInputDef& data_def, ExpectedEPNodeAssignment expected_ep_assignment, bool use_contrib_qdq = false) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; const std::vector> f32_inputs = {data_def}; @@ -116,11 +108,7 @@ static void RunSliceNonQDQOnHTP(const TestInputDef& data_def, const TestInputDef& steps_def, ExpectedEPNodeAssignment expected_ep_assignment) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; auto f32_model_builder = BuildOpTestCase("Slice", {data_def}, {starts_def, ends_def, axes_def, steps_def}, {}); RunQnnModelTest(f32_model_builder, @@ -207,4 +195,4 @@ TEST_F(QnnHTPBackendTests, SliceU8_MultAxes_LargeEnd) { } // namespace test } // namespace onnxruntime -#endif \ No newline at end of file +#endif diff --git a/onnxruntime/test/providers/qnn/split_op_test.cc b/onnxruntime/test/providers/qnn/split_op_test.cc index 52603b1be5045..bdd322168ee01 100644 --- a/onnxruntime/test/providers/qnn/split_op_test.cc +++ b/onnxruntime/test/providers/qnn/split_op_test.cc @@ -60,11 +60,7 @@ static void RunSplitOpTestOnCPU(const TestInputDef& input_def, ExpectedEPNodeAssignment expected_ep_assignment) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif + provider_options["backend_type"] = "cpu"; const bool split_is_input = opset >= 13; RunQnnModelTest(BuildSplitTestCase(input_def, split, split_is_input, axis, num_outputs), @@ -247,11 +243,7 @@ static void RunSplitOpTestOnHTP(const TestInputDef& input_def, ExpectedEPNodeAssignment expected_ep_assignment) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; const bool split_is_input = opset >= 13; RunQnnModelTest(BuildSplitTestCase(input_def, split, split_is_input, axis, num_outputs), @@ -271,11 +263,7 @@ static void RunQDQSplitOpTestOnHTP(const TestInputDef& input_def, bool use_contrib_qdq = false) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; const bool split_is_input = opset >= 13; diff --git a/onnxruntime/test/providers/qnn/squeeze_unsqueeze_op_test.cc b/onnxruntime/test/providers/qnn/squeeze_unsqueeze_op_test.cc index ead1843e843c1..43e24ce93a22b 100644 --- a/onnxruntime/test/providers/qnn/squeeze_unsqueeze_op_test.cc +++ b/onnxruntime/test/providers/qnn/squeeze_unsqueeze_op_test.cc @@ -23,11 +23,7 @@ static void RunSqueezeTestOnCPU(const std::string& op_type, // Squeeze or Unsqu int opset = 13) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif + provider_options["backend_type"] = "cpu"; RunQnnModelTest(BuildOpTestCase(op_type, {input_def}, {axes_def}, {}), provider_options, @@ -132,11 +128,7 @@ static void RunSqueezeTestOnHTP(const std::string& op_type, // Squeeze or Unsqu int opset = 13) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; RunQnnModelTest(BuildOpTestCase(op_type, {input_def}, {axes_def}, {}), provider_options, @@ -156,11 +148,7 @@ static void RunQDQSqueezeTestOnHTP(const std::string& op_type, bool use_contrib_qdq = false) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; auto f32_model_builder = BuildOpTestCase(op_type, {input_def}, {axes_def}, {}); @@ -215,11 +203,7 @@ TEST_F(QnnHTPBackendTests, Squeeze_Rank5_Rank2_f32) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; RunQnnModelTest(model_fn, @@ -272,11 +256,7 @@ TEST_F(QnnHTPBackendTests, Unsqueeze_Rank3_Rank5_f32) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; RunQnnModelTest(model_fn, diff --git a/onnxruntime/test/providers/qnn/tile_op_test.cc b/onnxruntime/test/providers/qnn/tile_op_test.cc index 023d6562c6f95..7ad6fcca95eb5 100644 --- a/onnxruntime/test/providers/qnn/tile_op_test.cc +++ b/onnxruntime/test/providers/qnn/tile_op_test.cc @@ -23,11 +23,7 @@ static void RunTileTestOnCPU(const TestInputDef& input_def, int opset = 13) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif + provider_options["backend_type"] = "cpu"; RunQnnModelTest(BuildOpTestCase("Tile", {input_def}, {repeats_def}, {}), provider_options, @@ -93,11 +89,7 @@ static void RunQDQTileTestOnHTP(const TestInputDef& input_def, bool use_contrib_qdq = false) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; auto f32_model_builder = BuildOpTestCase("Tile", {input_def}, {repeats_def}, {}); diff --git a/onnxruntime/test/providers/qnn/topk_op_test.cc b/onnxruntime/test/providers/qnn/topk_op_test.cc index b338dd727bf00..84e7299dbe3bb 100644 --- a/onnxruntime/test/providers/qnn/topk_op_test.cc +++ b/onnxruntime/test/providers/qnn/topk_op_test.cc @@ -43,11 +43,7 @@ static void RunTopKTestOnCPU(const TestInputDef& input_def, int opset = 19) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif + provider_options["backend_type"] = "cpu"; RunQnnModelTest(BuildTopKTestCase(input_def, k_def, attrs), provider_options, @@ -149,11 +145,7 @@ static void RunQDQTopKTestOnHTP(const TestInputDef& input_def, bool use_contrib_qdq = false) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; auto f32_model_builder = BuildTopKTestCase(input_def, k_def, attrs); diff --git a/onnxruntime/test/providers/qnn/transpose_htp_test.cc b/onnxruntime/test/providers/qnn/transpose_htp_test.cc index b7bec34f7dcbd..f206e517408bf 100644 --- a/onnxruntime/test/providers/qnn/transpose_htp_test.cc +++ b/onnxruntime/test/providers/qnn/transpose_htp_test.cc @@ -65,11 +65,7 @@ static void RunTransposeQDQTest(const TestInputDef& input_def, const std::vector& attrs, ExpectedEPNodeAssignment expected_ep_assignment) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; // Runs model with DQ-> Transpose -> Q and compares the outputs of the CPU and QNN EPs. @@ -94,11 +90,7 @@ static void RunTransposeNonQDQOnHTP(const TestInputDef& input_def, ExpectedEPNodeAssignment expected_ep_assignment, bool enable_fp16_precision = true) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; if (enable_fp16_precision) { provider_options["enable_htp_fp16_precision"] = "1"; @@ -139,4 +131,4 @@ TEST_F(QnnHTPBackendTests, TransposeFloatOnHTP) { } // namespace test } // namespace onnxruntime -#endif \ No newline at end of file +#endif diff --git a/onnxruntime/test/providers/qnn/where_htp_test.cc b/onnxruntime/test/providers/qnn/where_htp_test.cc index e1b0604b314e1..bb3e229bbc9f8 100644 --- a/onnxruntime/test/providers/qnn/where_htp_test.cc +++ b/onnxruntime/test/providers/qnn/where_htp_test.cc @@ -74,11 +74,7 @@ static void RunWhereQDQTest(const TestInputDef& condition_def, const TestInputDef& y_def, ExpectedEPNodeAssignment expected_ep_assignment) { ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif + provider_options["backend_type"] = "htp"; provider_options["offload_graph_io_quantization"] = "0"; // Runs model with DQ-> Where -> Q and compares the outputs of the CPU and QNN EPs. @@ -141,4 +137,4 @@ TEST_F(QnnHTPBackendTests, WhereLargeDataBroadcastTransformedU8) { } // namespace test } // namespace onnxruntime -#endif \ No newline at end of file +#endif diff --git a/onnxruntime/test/python/onnxruntime_test_python_ort_parallel.py b/onnxruntime/test/python/onnxruntime_test_python_ort_parallel.py new file mode 100644 index 0000000000000..c28bfb930e417 --- /dev/null +++ b/onnxruntime/test/python/onnxruntime_test_python_ort_parallel.py @@ -0,0 +1,154 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import ctypes +import sys +import threading +import time +import unittest + +import numpy as np +from helper import get_name + +import onnxruntime as onnxrt + + +class ThreadObj: + def __init__(self, model_path: str, iterations: int, idx: int, num_device: int, provider_options_list: list): + self.iterations = iterations + sess_opt = onnxrt.SessionOptions() + sess_opt.graph_optimization_level = onnxrt.GraphOptimizationLevel.ORT_DISABLE_ALL + sess_opt.execution_mode = onnxrt.ExecutionMode.ORT_PARALLEL # ORT will use thread from inter-op thread pool + self.inference_session = onnxrt.InferenceSession(model_path, sess_opt, provider_options_list[idx % num_device]) + self.input = { + "Input3": np.ones([1, 1, 28, 28], np.float32), + } + self.idx = idx + + def warmup(self): + print(f"[THREAD {self.idx}] running warmup") + self.inference_session.run(None, self.input) + print(f"[THREAD {self.idx}] warmup done") + + def run(self, thread_times, threads_complete): + for iter in range(self.iterations): + print(f"[THREAD {self.idx}] running iteration {iter}") + thread_times[self.idx] = time.time() + self.inference_session.run(None, self.input) + thread_times[self.idx] = time.time() + print(f"[THREAD {self.idx}] completed iteration {iter}") + threads_complete[0] += 1 + + +def thread_target(obj, thread_times, threads_complete): + obj.run(thread_times, threads_complete) + + +# This unittest class creates 10 threads, each thread creates its own inference session and runs one warmup sequentially. +# Once all threads finish their warmup run, all threads run multiple inference runs concurrently. +class TestParallelRun(unittest.TestCase): + def test_select_ep_to_run_ort_parallel_execution_mode(self): + if "TensorrtExecutionProvider" in onnxrt.get_available_providers(): + cuda_lib = self.load_cuda_lib() + device_cnt = self.cuda_device_count(cuda_lib) + assert device_cnt > 0 + print(f"Number of GPUs available: {device_cnt}") + self.run_inference_with_parallel_execution_mode("TensorrtExecutionProvider", device_cnt) + elif "CUDAExecutionProvider" in onnxrt.get_available_providers(): + cuda_lib = self.load_cuda_lib() + device_cnt = self.cuda_device_count(cuda_lib) + assert device_cnt > 0 + print(f"Number of GPUs available: {device_cnt}") + self.run_inference_with_parallel_execution_mode("CUDAExecutionProvider", device_cnt) + + def load_cuda_lib(self): + cuda_lib = None + if sys.platform == "win32": + cuda_lib = "nvcuda.dll" + elif sys.platform == "linux": + cuda_lib = "libcuda.so" + elif sys.platform == "darwin": + cuda_lib = "libcuda.dylib" + + if cuda_lib is not None: + try: + return ctypes.CDLL(cuda_lib) + except OSError: + pass + return None + + def cuda_device_count(self, cuda_lib): + if cuda_lib is None: + return -1 + num_device = ctypes.c_int() + cuda_lib.cuInit(0) + result = cuda_lib.cuDeviceGetCount(ctypes.byref(num_device)) + if result != 0: + error_str = ctypes.c_char_p() + cuda_lib.cuGetErrorString(result, ctypes.byref(error_str)) + print(f"cuDeviceGetCount failed with error code {result}: {error_str.value.decode()}") + return -1 + return num_device.value + + def run_inference_with_parallel_execution_mode(self, ep, num_device): + provider_options = [] + for i in range(num_device): + option = [ + ( + ep, + { + "device_id": i, + }, + ), + ] + provider_options.append(option) + + model_path = get_name("mnist.onnx") + iterations = 20 + hang_time = 60 + + num_threads = 10 + t_obj_list = [] + thread_list = [] + + threads_complete = [0] + thread_times = [0] * num_threads + + for tidx in range(num_threads): + obj = ThreadObj(model_path, iterations, tidx, num_device, provider_options) + t_obj_list.append(obj) + obj.warmup() + + for t_obj in t_obj_list: + thread = threading.Thread( + target=thread_target, + daemon=True, + args=( + t_obj, + thread_times, + threads_complete, + ), + ) + thread.start() + thread_list.append(thread) + + time.sleep(5) + while True: + for t_time in thread_times: + if time.time() - t_time < hang_time: + continue + else: + print("Hang occured, ending test") + exit(1) + if threads_complete[0] == num_threads: + break + time.sleep(5) + + for thread in thread_list: + thread.join() + + print("All threads completed") + + +if __name__ == "__main__": + unittest.main() diff --git a/onnxruntime/test/python/onnxruntime_test_python_symbolic_shape_infer.py b/onnxruntime/test/python/onnxruntime_test_python_symbolic_shape_infer.py index d311b4b8517cf..5267ffcc65ab7 100644 --- a/onnxruntime/test/python/onnxruntime_test_python_symbolic_shape_infer.py +++ b/onnxruntime/test/python/onnxruntime_test_python_symbolic_shape_infer.py @@ -644,6 +644,87 @@ def test_matmulnbits(self): ] self._check_shapes(graph, inferred.graph, expected_shapes) + def test_qlinear_binary(self): + """ + Test ONNX QLinearAdd op ('com.microsoft' domain). . + Check that the output shape is propagated from the inputs to the op with broadcasting. + """ + initializers = [ + helper.make_tensor( + "A_scale", + TensorProto.FLOAT, + [], + [0.7], + ), + helper.make_tensor( + "A_zero_point", + TensorProto.UINT8, + [], + [158], + ), + helper.make_tensor( + "B_scale", + TensorProto.FLOAT, + [], + [0.02], + ), + helper.make_tensor( + "B_zero_point", + TensorProto.UINT8, + [], + [5], + ), + helper.make_tensor( + "C_scale", + TensorProto.FLOAT, + [], + [0.26], + ), + helper.make_tensor( + "C_zero_point", + TensorProto.UINT8, + [], + [0], + ), + ] + + nodes = [ + helper.make_node( + "QLinearAdd", + inputs=[ + "A", + "A_scale", + "A_zero_point", + "B", + "B_scale", + "B_zero_point", + "C_scale", + "C_zero_point", + ], + outputs=["C"], + domain="com.microsoft", + ), + ] + + inputs = [ + helper.make_tensor_value_info("A", TensorProto.UINT8, ["b", 4, 128]), + helper.make_tensor_value_info("B", TensorProto.UINT8, ["b", 1, 4, 1, 128]), + ] + + outputs = [ + helper.make_tensor_value_info("C", TensorProto.UNDEFINED, None), + ] + + graph = helper.make_graph(nodes, "QLinearAdd_Test", inputs, outputs, initializers) + model = helper.make_model(graph) + + inferred = SymbolicShapeInference.infer_shapes(model, auto_merge=True) + + expected_shapes = [ + helper.make_tensor_value_info("C", TensorProto.UINT8, ["b", 1, 4, 4, 128]), + ] + self._check_shapes(graph, inferred.graph, expected_shapes) + class TestSymbolicShapeInferenceForSlice(unittest.TestCase): def check_slice_of_concat(self, input_dims, start, end, step, expected_output_dim): diff --git a/onnxruntime/test/python/transformers/sharded_moe/test_sharded_moe.py b/onnxruntime/test/python/transformers/sharded_moe/test_sharded_moe.py index 42682d67e94ec..2d29135726839 100644 --- a/onnxruntime/test/python/transformers/sharded_moe/test_sharded_moe.py +++ b/onnxruntime/test/python/transformers/sharded_moe/test_sharded_moe.py @@ -6,22 +6,28 @@ import unittest import numpy as np -from mpi4py import MPI from onnx import TensorProto, helper import onnxruntime -np.random.seed(3) +try: + from mpi4py import MPI + + comm = MPI.COMM_WORLD +except (ImportError, RuntimeError): + comm = None -comm = MPI.COMM_WORLD +has_mpi = comm is not None + +np.random.seed(3) def get_rank(): - return comm.Get_rank() + return comm.Get_rank() if comm else 0 def get_size(): - return comm.Get_size() + return comm.Get_size() if comm else 0 def print_out(*args): @@ -254,7 +260,7 @@ def run_ort_with_parity_check( ) -def test_moe_with_tensor_parallelism( +def run_moe_with_tensor_parallelism( hidden_size, inter_size, num_experts, @@ -327,7 +333,7 @@ def get_fc2_tensor_shards(expert_weights): ) -def test_moe_with_expert_parallelism( +def run_moe_with_expert_parallelism( hidden_size, inter_size, num_experts, @@ -390,19 +396,22 @@ def test_moe_with_expert_parallelism( class TestMoE(unittest.TestCase): def test_moe_parallelism(self): + if not has_mpi: + self.skipTest("No MPI support") + for hidden_size in [128, 1024]: for inter_size in [512, 2048]: for num_experts in [64]: for num_rows in [1024]: print_out("EP") - test_moe_with_expert_parallelism( + run_moe_with_expert_parallelism( hidden_size, inter_size, num_experts, num_rows, ) print_out("TP") - test_moe_with_tensor_parallelism( + run_moe_with_tensor_parallelism( hidden_size, inter_size, num_experts, diff --git a/onnxruntime/test/python/transformers/test_data/models/gemma3-vision-attention_fp16.onnx b/onnxruntime/test/python/transformers/test_data/models/gemma3-vision-attention_fp16.onnx new file mode 100644 index 0000000000000..49e805169ee45 Binary files /dev/null and b/onnxruntime/test/python/transformers/test_data/models/gemma3-vision-attention_fp16.onnx differ diff --git a/onnxruntime/test/python/transformers/test_data/models/gemma3-vision-attention_fp32.onnx b/onnxruntime/test/python/transformers/test_data/models/gemma3-vision-attention_fp32.onnx new file mode 100644 index 0000000000000..7fca335f13731 Binary files /dev/null and b/onnxruntime/test/python/transformers/test_data/models/gemma3-vision-attention_fp32.onnx differ diff --git a/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_attention_with_sln_fused.onnx b/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_attention_with_sln_fused.onnx index 1bf93cde504da..a0e65a0023612 100644 Binary files a/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_attention_with_sln_fused.onnx and b/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_attention_with_sln_fused.onnx differ diff --git a/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_with_past_self_mha_fused.onnx b/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_with_past_self_mha_fused.onnx index deaeb206acee4..e51215bff7d30 100644 Binary files a/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_with_past_self_mha_fused.onnx and b/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_with_past_self_mha_fused.onnx differ diff --git a/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_with_past_self_mha_split_bias_fused.onnx b/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_with_past_self_mha_split_bias_fused.onnx index ca7f33a3f1d8d..c50162eb5bf8e 100644 Binary files a/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_with_past_self_mha_split_bias_fused.onnx and b/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_with_past_self_mha_split_bias_fused.onnx differ diff --git a/onnxruntime/test/python/transformers/test_gelu_fusions.py b/onnxruntime/test/python/transformers/test_gelu_fusions.py index 94b969ad5377d..11ae1401ff8ed 100644 --- a/onnxruntime/test/python/transformers/test_gelu_fusions.py +++ b/onnxruntime/test/python/transformers/test_gelu_fusions.py @@ -3,6 +3,7 @@ import unittest import torch +from parameterized import parameterized from parity_utilities import find_transformers_source if find_transformers_source(): @@ -43,16 +44,6 @@ def forward(self, x): return 0.5 * x * (1.0 + torch.tanh(0.7978845608028654 * x * (1.0 + 0.044715 * x * x))) -test_cases = [ - ("huggingface", "Gelu", HuggingfaceGelu), - ("huggingface", "FastGelu", HuggingfaceFastGelu), - ("huggingface", "QuickGelu", HuggingfaceQuickGelu), - ("huggingface", "FastGelu", HuggingfaceTorchGeluTanh), - ("megatron", "Gelu", MegatronGelu), - ("megatron", "FastGelu", MegatronFastGelu), -] - - class TestGeluFusions(unittest.TestCase): def verify_node_count(self, bert_model, expected_node_count, test_name): for op_type, count in expected_node_count.items(): @@ -62,25 +53,47 @@ def verify_node_count(self, bert_model, expected_node_count, test_name): print(f"{op}: {len(bert_model.get_nodes_by_op_type(op))} expected={counter}") self.assertEqual(len(bert_model.get_nodes_by_op_type(op_type)), count) - def test_fusions(self): - for test_case in test_cases: - source, operator, model_class = test_case - model = model_class() - dummy_input = torch.ones(3, dtype=torch.float32) - test_name = f"{operator}_{source}" - onnx_path = f"{test_name}.onnx" - torch.onnx.export( - model, - (dummy_input), - onnx_path, - input_names=["input"], - output_names=["output"], - ) - optimizer = optimize_model(onnx_path, "bert") - # optimizer.save_model_to_file(f"{operator}_{source}_opt.onnx") - os.remove(onnx_path) - expected_node_count = {operator: 1} - self.verify_node_count(optimizer, expected_node_count, test_name) + @parameterized.expand( + [ + (("huggingface", "Gelu", HuggingfaceGelu), True), + (("huggingface", "FastGelu", HuggingfaceFastGelu), True), + (("huggingface", "QuickGelu", HuggingfaceQuickGelu), True), + (("huggingface", "FastGelu", HuggingfaceTorchGeluTanh), True), + (("megatron", "Gelu", MegatronGelu), True), + (("megatron", "FastGelu", MegatronFastGelu), True), + (("huggingface", "Gelu", HuggingfaceGelu), False), + (("huggingface", "FastGelu", HuggingfaceFastGelu), False), + (("huggingface", "QuickGelu", HuggingfaceQuickGelu), False), + (("huggingface", "FastGelu", HuggingfaceTorchGeluTanh), False), + (("megatron", "Gelu", MegatronGelu), False), + (("megatron", "FastGelu", MegatronFastGelu), False), + ] + ) + def test_fusions(self, test_case, dynamo): + source, operator, model_class = test_case + model = model_class() + dummy_input = torch.ones(3, dtype=torch.float32) + test_name = f"{operator}_{source}" + onnx_path = f"{test_name}.onnx" + torch.onnx.export( + model, + (dummy_input,), + onnx_path, + input_names=["input"], + output_names=["output"], + dynamo=dynamo, + optimize=True, # Only meaningful when dynamo is True + ) + optimizer = optimize_model(onnx_path, "bert") + # optimizer.save_model_to_file(f"{operator}_{source}_opt.onnx") + os.remove(onnx_path) + # Remove the associated .data file (dynamo) + data_path = onnx_path + ".data" + if os.path.exists(data_path): + os.remove(data_path) + expected_node_count = {operator: 1} + + self.verify_node_count(optimizer, expected_node_count, test_name) if __name__ == "__main__": diff --git a/onnxruntime/test/python/transformers/test_gemma3_vision.py b/onnxruntime/test/python/transformers/test_gemma3_vision.py new file mode 100644 index 0000000000000..4727d2c8030d2 --- /dev/null +++ b/onnxruntime/test/python/transformers/test_gemma3_vision.py @@ -0,0 +1,216 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +import os +import unittest + +import onnx +import torch +from parameterized import parameterized +from parity_utilities import find_transformers_source + +if find_transformers_source(): + from dynamo_onnx_helper import DynamoOnnxHelper + from fusion_options import FusionOptions + from onnx_model import OnnxModel + from optimizer import optimize_model +else: + from onnxruntime.transformers.dynamo_onnx_helper import DynamoOnnxHelper + from onnxruntime.transformers.fusion_options import FusionOptions + from onnxruntime.transformers.onnx_model import OnnxModel + from onnxruntime.transformers.optimizer import optimize_model + + +# https://github.com/huggingface/transformers/blob/af9b2eaa54c150741f298d6db939af6328e1dc38/src/transformers/models/siglip/modeling_siglip.py#L363 +class SiglipAttention(torch.nn.Module): + """Multi-headed attention from 'Attention Is All You Need' paper""" + + # Copied from transformers.models.clip.modeling_clip.CLIPAttention.__init__ + def __init__(self): + super().__init__() + self.embed_dim = 20 + self.num_heads = 2 + self.head_dim = self.embed_dim // self.num_heads + if self.head_dim * self.num_heads != self.embed_dim: + raise ValueError( + f"embed_dim must be divisible by num_heads (got `embed_dim`: {self.embed_dim} and `num_heads`:" + f" {self.num_heads})." + ) + self.scale = self.head_dim**-0.5 + + self.k_proj = torch.nn.Linear(self.embed_dim, self.embed_dim) + self.v_proj = torch.nn.Linear(self.embed_dim, self.embed_dim) + self.q_proj = torch.nn.Linear(self.embed_dim, self.embed_dim) + self.out_proj = torch.nn.Linear(self.embed_dim, self.embed_dim) + + self.k_proj.weight.data.fill_(1) + self.v_proj.weight.data.fill_(1) + self.q_proj.weight.data.fill_(1) + self.out_proj.weight.data.fill_(1) + self.k_proj.bias.data.fill_(1) + self.v_proj.bias.data.fill_(1) + self.q_proj.bias.data.fill_(1) + self.out_proj.bias.data.fill_(1) + + def forward( + self, + hidden_states: torch.Tensor, + attention_mask: torch.Tensor | None = None, + output_attentions: bool | None = False, + ) -> tuple[torch.Tensor, torch.Tensor | None]: + """Input shape: Batch x Time x Channel""" + + batch_size, q_len, _ = hidden_states.size() + + query_states = self.q_proj(hidden_states) + key_states = self.k_proj(hidden_states) + value_states = self.v_proj(hidden_states) + + query_states = query_states.view(batch_size, q_len, self.num_heads, self.head_dim).transpose(1, 2) + key_states = key_states.view(batch_size, q_len, self.num_heads, self.head_dim).transpose(1, 2) + value_states = value_states.view(batch_size, q_len, self.num_heads, self.head_dim).transpose(1, 2) + + k_v_seq_len = key_states.shape[-2] + attn_weights = torch.matmul(query_states, key_states.transpose(2, 3)) * self.scale + + if attn_weights.size() != (batch_size, self.num_heads, q_len, k_v_seq_len): + raise ValueError( + f"Attention weights should be of size {(batch_size, self.num_heads, q_len, k_v_seq_len)}, but is" + f" {attn_weights.size()}" + ) + + if attention_mask is not None: + if attention_mask.size() != (batch_size, 1, q_len, k_v_seq_len): + raise ValueError( + f"Attention mask should be of size {(batch_size, 1, q_len, k_v_seq_len)}, but is {attention_mask.size()}" + ) + attn_weights = attn_weights + attention_mask + + # upcast attention to fp32 + attn_weights = torch.nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query_states.dtype) + attn_output = torch.matmul(attn_weights, value_states) + + if attn_output.size() != (batch_size, self.num_heads, q_len, self.head_dim): + raise ValueError( + f"`attn_output` should be of size {(batch_size, self.num_heads, q_len, self.head_dim)}, but is" + f" {attn_output.size()}" + ) + + attn_output = attn_output.transpose(1, 2).contiguous() + attn_output = attn_output.reshape(batch_size, q_len, self.embed_dim) + + attn_output = self.out_proj(attn_output) + + return attn_output, attn_weights + + +class Gemma3VSIGLIPAttentionAndLayerNorm(torch.nn.Module): + def __init__(self): + super().__init__() + self.attn = SiglipAttention() + self.ln = torch.nn.LayerNorm(20, eps=1e-05) + + def forward(self, x): + # SkipLayerNorm ------+ + # | | + # Attention | + # | | + # MatMul | + # | | + # SkipLayerNorm ------+ + + # SkipLayerNorm + x = x + x + x = self.ln(x) + residual = x + + # Attention + MatMul + x, _ = self.attn(x) + + # SkipLayerNorm + x = residual + x + x = self.ln(x) + return x + + +class TestFusion(unittest.TestCase): + def verify_fusion(self, optimized_model, expected_model_filename): + optimized_model.topological_sort(is_deterministic=True) + + expected_model_path = os.path.join(os.path.dirname(__file__), "test_data", "models", expected_model_filename) + expected_model = OnnxModel(onnx.load(expected_model_path)) + expected_model.topological_sort(is_deterministic=True) + + nodes = optimized_model.model.graph.node + self.assertEqual(len(nodes), len(expected_model.model.graph.node)) + + for i in range(len(nodes)): + self.assertEqual(nodes[i], expected_model.model.graph.node[i]) + + for expected_initializer in expected_model.model.graph.initializer: + self.assertTrue( + OnnxModel.has_same_value( + optimized_model.get_initializer(expected_initializer.name), + expected_initializer, + ) + ) + + def export(self, model, inputs) -> onnx.ModelProto: + with torch.no_grad(): + onnx_program = torch.onnx.export( + model, + args=inputs, + # f=os.path.join(os.path.dirname(__file__), "export.onnx"), + dynamo=True, + optimize=True, + ) + return onnx_program.model_proto # type: ignore + + def tearDown(self): + paths = [ + os.path.join(os.path.dirname(__file__), "export.onnx"), + os.path.join(os.path.dirname(__file__), "export.onnx.data"), + ] + for path in paths: + if os.path.exists(path): + os.remove(path) + + @parameterized.expand( + [ + (torch.float32, "gemma3-vision-attention_fp32.onnx"), + (torch.float16, "gemma3-vision-attention_fp16.onnx"), + ] + ) + def test_gemma3_vision_attention(self, dtype, model_name): + model = Gemma3VSIGLIPAttentionAndLayerNorm().eval().to(dtype) + inputs = (torch.randn(1, 2, 20, dtype=dtype),) + original_model = self.export(model, inputs) + + # TODO(titaiwang): Upstream these processings to onnxscript pass + onnx_model_wrapper = DynamoOnnxHelper(original_model) + onnx_model_wrapper.convert_constants_to_initializers() + onnx_model_wrapper.clear_metadata() + model_path = os.path.join(os.path.dirname(__file__), "export.onnx") + onnx_model_wrapper.model.save_model_to_file( + model_path, + use_external_data_format=True, + all_tensors_to_one_file=True, + convert_attribute=True, + ) + + options = FusionOptions("clip") + optimized_model = optimize_model( + model_path, + model_type="clip", + num_heads=2, + hidden_size=20, + optimization_options=options, + opt_level=0, + ) + self.verify_fusion(optimized_model, model_name) + + +if __name__ == "__main__": + unittest.main() diff --git a/onnxruntime/test/python/transformers/test_generation.py b/onnxruntime/test/python/transformers/test_generation.py index 88f870e92d558..c5cf8a07f557d 100644 --- a/onnxruntime/test/python/transformers/test_generation.py +++ b/onnxruntime/test/python/transformers/test_generation.py @@ -28,6 +28,10 @@ from onnxruntime.transformers.models.whisper.convert_to_onnx import main as run_whisper +def has_cuda_environment(): + return torch.cuda.is_available() and "CUDAExecutionProvider" in get_available_providers() + + class TestBeamSearchGpt(unittest.TestCase): """Test BeamSearch for GPT-2 model""" @@ -49,7 +53,7 @@ def setUp(self): # "The selloff in tech shares deepened", # "Abortion rights take center stage", ] - self.enable_cuda = torch.cuda.is_available() and "CUDAExecutionProvider" in get_available_providers() + self.enable_cuda = has_cuda_environment() self.remove_onnx_files() def tearDown(self): @@ -176,112 +180,253 @@ def test_external_data(self): ) -class TestBeamSearchT5(unittest.TestCase): - """Test BeamSearch for T5 model""" +def get_tiny_t5_model_dir(): + """Get the path to the tiny T5 model directory.""" + # This function is used to get the path to the tiny T5 model directory. + # It is used in the TestBeamSearchT5 and TestBeamSearchT5Fp16 classes. - def setUp(self): - self.model_name = "t5-small" - self.decoder_onnx_path = os.path.join(".", "onnx_models", "t5-small_decoder.onnx") - self.encoder_onnx_path = os.path.join(".", "onnx_models", "t5-small_encoder_decoder_init.onnx") - self.beam_search_onnx_path = os.path.join(".", "onnx_models", "t5_small_beam_search.onnx") - self.default_arguments = [ - f"-m {self.model_name}", + # Path relative to the build\Release directory, where transformers test is launched in pipeline. + tiny_model_dir = os.path.join( + "testdata", + "transformers", + "tiny_t5", + ) + if os.path.exists(tiny_model_dir): + return os.path.normpath(tiny_model_dir) + + # The path is relative to the current file's directory. + tiny_model_dir = os.path.join( + os.path.dirname(__file__), + "..", + "..", + "testdata", + "transformers", + "tiny_t5", + ) + return os.path.normpath(tiny_model_dir) + + +use_tiny_model = True + + +class TestBeamSearchT5(unittest.TestCase): + """Test BeamSearch for T5 model with fp32 in CPU""" + + @classmethod + def setUpClass(cls): + tiny_model_dir = get_tiny_t5_model_dir() + model_name = "tiny_t5" if use_tiny_model and os.path.exists(tiny_model_dir) else "t5-small" + cls.model_name = tiny_model_dir if model_name == "tiny_t5" else "t5-small" + cls.decoder_onnx_path = os.path.join(".", "t5_onnx_models", f"{model_name}_decoder.onnx") + cls.encoder_onnx_path = os.path.join(".", "t5_onnx_models", f"{model_name}_encoder.onnx") + cls.beam_search_onnx_path = os.path.join(".", "t5_onnx_models", f"{model_name}_beam_search.onnx") + cls.default_arguments = [ + f"-m {cls.model_name}", "--model_type t5", - f"--decoder_onnx {self.decoder_onnx_path}", - f"--encoder_decoder_init_onnx {self.encoder_onnx_path}", - f"--output {self.beam_search_onnx_path}", + f"--decoder_onnx {cls.decoder_onnx_path}", + f"--encoder_decoder_init_onnx {cls.encoder_onnx_path}", + f"--output {cls.beam_search_onnx_path}", "--output_sequences_score", "--repetition_penalty 2.0", ] - self.enable_cuda = torch.cuda.is_available() and "CUDAExecutionProvider" in get_available_providers() + # Remove onnx files if existed for any reason. + cls.remove_onnx_files() - export_t5_onnx_models( - self.model_name, + # This is in class setup so that we only export t5 model once. + paths = export_t5_onnx_models( + cls.model_name, os.path.join(".", "cache_models"), - os.path.join(".", "onnx_models"), + os.path.join(".", "t5_onnx_models"), use_gpu=False, use_external_data_format=False, optimize_onnx=False, - precision=Precision.FLOAT32, + precision=Precision.FLOAT32.value, verbose=False, use_decoder_start_token=False, - merge_encoder_and_decoder_init=True, overwrite=True, disable_auto_mixed_precision=False, use_int32_inputs=True, ) + assert len(paths) == 2 - self.sentences = [ + cls.sentences = [ "translate English to French: The product is released", "summarize: research continues to show that pets bring real health benefits to their owners. Having a dog around can lead to lower levels of stress for both adults and kids.", ] - if os.path.exists(self.beam_search_onnx_path): - os.remove(self.beam_search_onnx_path) + @classmethod + def remove_onnx_files(cls, beam_search_onnx_only: bool = False): + if os.path.exists(cls.beam_search_onnx_path): + os.remove(cls.beam_search_onnx_path) + if os.path.exists(cls.beam_search_onnx_path + ".data"): + os.remove(cls.beam_search_onnx_path + ".data") - def tearDown(self): - self.remove_onnx_files() + if not beam_search_onnx_only: + if os.path.exists(cls.encoder_onnx_path): + os.remove(cls.encoder_onnx_path) + if os.path.exists(cls.decoder_onnx_path): + os.remove(cls.decoder_onnx_path) - def remove_onnx_files(self): - if os.path.exists(self.beam_search_onnx_path): - os.remove(self.beam_search_onnx_path) + @classmethod + def tearDownClass(cls): + # cls.remove_onnx_files() + pass - if os.path.exists(self.decoder_onnx_path): - os.remove(self.decoder_onnx_path) + def setUp(self): + pass - if os.path.exists(self.encoder_onnx_path): - os.remove(self.encoder_onnx_path) + def tearDown(self): + # self.remove_onnx_files(beam_search_onnx_only=True) + pass - def run_beam_search(self, extra_arguments: str, sentences=None, append_arguments=True): - if append_arguments: - arguments = " ".join([*self.default_arguments, extra_arguments]).split() - else: - arguments = extra_arguments.split() + def run_beam_search(self, extra_arguments: str): + arguments = " ".join([*self.default_arguments, extra_arguments]).split() # Test CPU - result = run(arguments, sentences=self.sentences if sentences is None else sentences) + result = run(arguments) self.assertTrue(result["parity"], f"ORT and PyTorch result is different on CPU for arguments {arguments}") - # Test GPU - if self.enable_cuda: - if "--use_gpu" not in arguments: - arguments.append("--use_gpu") - result = run(arguments, sentences=self.sentences if sentences is None else sentences) - self.assertTrue(result["parity"], f"ORT and PyTorch result is different on GPU for arguments {arguments}") - - os.remove(self.beam_search_onnx_path) - - @pytest.mark.slow def test_return_sequences(self): for return_sequences in [1, 2]: self.run_beam_search(f"--num_return_sequences {return_sequences}") - @pytest.mark.slow def test_early_stopping(self): self.run_beam_search("--early_stopping") - @pytest.mark.slow def test_length_penalty(self): for length_penalty in [0.5, 2.0]: self.run_beam_search(f"--length_penalty {length_penalty}") - @pytest.mark.slow def test_no_repeat_ngram(self): for ngram_size in [1, 2]: self.run_beam_search(f"--no_repeat_ngram_size {ngram_size}") - @pytest.mark.slow def test_custom_attention_mask(self): self.run_beam_search("--custom_attention_mask") - @pytest.mark.slow def test_external_data(self): - self.run_beam_search( - f"-m t5-small --model_type t5 -e --output {self.beam_search_onnx_path}", - sentences=None, - append_arguments=False, - ) + self.run_beam_search("-e") + + +@unittest.skipUnless( + has_cuda_environment(), + "skip since there is no cuda environment.", +) +class TestBeamSearchT5Fp16(unittest.TestCase): + """Test BeamSearch for T5 model with fp16 in GPU""" + + @classmethod + def setUpClass(cls): + tiny_model_dir = get_tiny_t5_model_dir() + tiny_model_dir = os.path.normpath(tiny_model_dir) + cls.model_name = "tiny_t5" if use_tiny_model and os.path.exists(tiny_model_dir) else "t5-small" + cls.model_id = tiny_model_dir if cls.model_name == "tiny_t5" else "t5-small" + cls.beam_search_onnx_path = os.path.join(".", "onnx_models", f"{cls.model_name}_beam_search_fp16.onnx") + cls.default_arguments = [ + f"-m {cls.model_id}", + "--model_type t5", + f"--output {cls.beam_search_onnx_path}", + "--min_length 2", + "--max_length 16", + "--use_gpu", + "-p fp16", + ] + + cls.sentences = [ + "translate English to French: The product is released", + "summarize: research continues to show that pets bring real health benefits to their owners. Having a dog around can lead to lower levels of stress for both adults and kids.", + ] + + cls.remove_onnx_files() + + @classmethod + def remove_onnx_files(cls): + model_name = cls.model_name + for file in [ + f"{model_name}_beam_search_fp16.onnx", + f"{model_name}_encoder.onnx", + f"{model_name}_encoder_fp16.onnx", + f"{model_name}_decoder.onnx", + f"{model_name}_decoder_fp16.onnx", + ]: + if os.path.exists(os.path.join(".", "onnx_models", file)): + os.remove(os.path.join(".", "onnx_models", file)) + if os.path.exists(os.path.join(".", "onnx_models", file + ".data")): + os.remove(os.path.join(".", "onnx_models", file + ".data")) + + def setUp(self): + pass + + def tearDown(self): + self.remove_onnx_files() + + def check_encoder_fusion(self): + model_name = self.model_name + onnx_path = os.path.join(".", "onnx_models", f"{model_name}_encoder_fp16.onnx") + + model = onnx.load_model(onnx_path, format=None, load_external_data=True) + from onnxruntime.transformers.onnx_model import OnnxModel + + onnx_model = OnnxModel(model) + op_counters = onnx_model.get_operator_statistics() + print("encoder ops", op_counters) + + expected_node_count = { + "RelativePositionBias": 1, + "SimplifiedLayerNormalization": 5 if use_tiny_model else 13, + "Attention": 2 if use_tiny_model else 6, + } + for key, value in expected_node_count.items(): + self.assertIn(key, op_counters, f"Expected {key} to be in op_counters") + self.assertEqual(op_counters[key], value, f"Expected {key} to be {value}, but got {op_counters[key]}") + + def check_decoder_fusion(self): + model_name = self.model_name + onnx_path = os.path.join(".", "onnx_models", f"{model_name}_decoder_fp16.onnx") + + model = onnx.load_model(onnx_path, format=None, load_external_data=True) + from onnxruntime.transformers.onnx_model import OnnxModel + + onnx_model = OnnxModel(model) + op_counters = onnx_model.get_operator_statistics() + print("decoder ops", op_counters) + + expected_node_count = { + "RelativePositionBias": 1, + "SimplifiedLayerNormalization": 7 if use_tiny_model else 19, + "MultiHeadAttention": 4 if use_tiny_model else 12, + } + for key, value in expected_node_count.items(): + self.assertIn(key, op_counters, f"Expected {key} to be in op_counters") + self.assertEqual(op_counters[key], value, f"Expected {key} to be {value}, but got {op_counters[key]}") + + def run_beam_search(self, extra_arguments: str): + arguments = " ".join([*self.default_arguments, extra_arguments]).split() + result = run(arguments) + self.assertTrue(result["parity"], f"ORT and PyTorch result is different on GPU for arguments {arguments}") + + def test_return_sequences(self): + for return_sequences in [1, 2]: + self.run_beam_search(f"--num_return_sequences {return_sequences}") + + def test_early_stopping(self): + self.run_beam_search("--early_stopping") + + def test_length_penalty(self): + for length_penalty in [0.5, 2.0]: + self.run_beam_search(f"--length_penalty {length_penalty}") + + def test_no_repeat_ngram(self): + for ngram_size in [1, 2]: + self.run_beam_search(f"--no_repeat_ngram_size {ngram_size}") + + def test_external_data(self): + self.run_beam_search("-e") + + # Ensure fusion is done correctly. + self.check_encoder_fusion() + self.check_decoder_fusion() class TestBeamSearchWhisper(unittest.TestCase): @@ -292,9 +437,9 @@ def setUp(self): self.pytorch_folder = "cache_models" self.onnx_folder = "onnx_models" self.decoder_onnx_path = os.path.join(".", self.onnx_folder, "whisper-tiny_decoder.onnx") - self.encoder_onnx_path = os.path.join(".", self.onnx_folder, "whisper-tiny_encoder_decoder_init.onnx") + self.encoder_onnx_path = os.path.join(".", self.onnx_folder, "whisper-tiny_encoder.onnx") self.beam_search_onnx_path = os.path.join(".", self.onnx_folder, "whisper-tiny_beamsearch.onnx") - self.enable_cuda = torch.cuda.is_available() and "CUDAExecutionProvider" in get_available_providers() + self.enable_cuda = has_cuda_environment() self.base_arguments = [ "-m", diff --git a/onnxruntime/test/python/transformers/test_gqa_cpu.py b/onnxruntime/test/python/transformers/test_gqa_cpu.py index 77b4b326bf645..461c243b82212 100644 --- a/onnxruntime/test/python/transformers/test_gqa_cpu.py +++ b/onnxruntime/test/python/transformers/test_gqa_cpu.py @@ -12,6 +12,7 @@ import math import random import unittest +from dataclasses import dataclass import numpy import torch @@ -29,11 +30,12 @@ GREEN = "\033[32m" RESET = "\033[0m" -ORT_TYPE = TensorProto.FLOAT -TORCH_TYPE = torch.float16 if ORT_TYPE == TensorProto.FLOAT16 else torch.float32 -NUMPY_TYPE = numpy.float16 if ORT_TYPE == TensorProto.FLOAT16 else numpy.float32 -RTOL = 3e-2 if ORT_TYPE == TensorProto.FLOAT16 else 1e-3 -ATOL = RTOL +# These will now be set dynamically in tests +ORT_TYPE = None +TORCH_TYPE = None +NUMPY_TYPE = None +RTOL = None +ATOL = None class Formats: @@ -41,42 +43,30 @@ class Formats: BNSH = 1 +@dataclass class Config: - batch_size = 0 - sequence_length = 0 - kv_sequence_length = 0 - past_sequence_length = 0 - num_heads = 0 - kv_num_heads = 0 - head_size = 0 - - def __init__(self, b, s, s2, sp, n, n2, h): - self.batch_size = b - self.sequence_length = s - self.kv_sequence_length = s2 - self.past_sequence_length = sp - self.num_heads = n - self.kv_num_heads = n2 - self.head_size = h - - + batch_size: int = 0 + sequence_length: int = 0 + kv_sequence_length: int = 0 + past_sequence_length: int = 0 + num_heads: int = 0 + kv_num_heads: int = 0 + head_size: int = 0 + has_position_ids: bool = False + has_attention_bias: bool = False + + +@dataclass class PromptConfig: - batch_size = 0 - q_sequence_length = 0 - kv_sequence_length = 0 - buffer_sequence_length = 0 - num_heads = 0 - kv_num_heads = 0 - head_size = 0 - - def __init__(self, b, sq, skv, sb, n, n2, h): - self.batch_size = b - self.q_sequence_length = sq - self.kv_sequence_length = skv - self.buffer_sequence_length = sb - self.num_heads = n - self.kv_num_heads = n2 - self.head_size = h + batch_size: int = 0 + q_sequence_length: int = 0 + kv_sequence_length: int = 0 + buffer_sequence_length: int = 0 + num_heads: int = 0 + kv_num_heads: int = 0 + head_size: int = 0 + has_position_ids: bool = False + has_attention_bias: bool = False # LLaMA Microsoft model @@ -149,6 +139,7 @@ def forward(self, x, cos, sin, pos, interleaved): def create_group_query_attention_graph_prompt( config, + ort_type, past_kv_format=Formats.BSNH, share_buffer=True, local_window_size=-1, @@ -173,6 +164,8 @@ def create_group_query_attention_graph_prompt( "total_sequence_length", "cos_cache" if rotary else "", "sin_cache" if rotary else "", + "position_ids" if config.has_position_ids else "", + "attention_bias" if config.has_attention_bias else "", ], ["output", "present_key", "present_value"], "GroupQueryAttention_0", @@ -192,7 +185,7 @@ def create_group_query_attention_graph_prompt( graph_input = [ helper.make_tensor_value_info( "query", - ORT_TYPE, + ort_type, [ config.batch_size, config.q_sequence_length, @@ -218,7 +211,7 @@ def create_group_query_attention_graph_prompt( graph_input += [ helper.make_tensor_value_info( "key", - ORT_TYPE, + ort_type, [ config.batch_size, config.kv_sequence_length, @@ -227,7 +220,7 @@ def create_group_query_attention_graph_prompt( ), helper.make_tensor_value_info( "value", - ORT_TYPE, + ort_type, [ config.batch_size, config.kv_sequence_length, @@ -239,7 +232,7 @@ def create_group_query_attention_graph_prompt( graph_input += [ helper.make_tensor_value_info( "past_key", - ORT_TYPE, + ort_type, [ config.batch_size, past_kv_seqlen if past_kv_format == Formats.BSNH else config.kv_num_heads, @@ -249,7 +242,7 @@ def create_group_query_attention_graph_prompt( ), helper.make_tensor_value_info( "past_value", - ORT_TYPE, + ort_type, [ config.batch_size, past_kv_seqlen if past_kv_format == Formats.BSNH else config.kv_num_heads, @@ -262,7 +255,7 @@ def create_group_query_attention_graph_prompt( graph_input += [ helper.make_tensor_value_info( "cos_cache", - ORT_TYPE, + ort_type, [ config.buffer_sequence_length if share_buffer else config.kv_sequence_length, (math.floor(config.head_size / 16) * 16) // 2, @@ -270,7 +263,7 @@ def create_group_query_attention_graph_prompt( ), helper.make_tensor_value_info( "sin_cache", - ORT_TYPE, + ort_type, [ config.buffer_sequence_length if share_buffer else config.kv_sequence_length, (math.floor(config.head_size / 16) * 16) // 2, @@ -278,15 +271,33 @@ def create_group_query_attention_graph_prompt( ), ] + if config.has_position_ids: + graph_input += [ + helper.make_tensor_value_info( + "position_ids", + TensorProto.INT64, + [config.batch_size, config.kv_sequence_length], + ), + ] + + if config.has_attention_bias: + graph_input += [ + helper.make_tensor_value_info( + "attention_bias", + ort_type, + [config.batch_size, 1, config.kv_sequence_length, config.kv_sequence_length], + ), + ] + graph_output = [ helper.make_tensor_value_info( "output", - ORT_TYPE, + ort_type, [config.batch_size, config.q_sequence_length, config.num_heads * config.head_size], ), helper.make_tensor_value_info( "present_key", - ORT_TYPE, + ort_type, [ config.batch_size, present_kv_seqlen if past_kv_format == Formats.BSNH else config.kv_num_heads, @@ -296,7 +307,7 @@ def create_group_query_attention_graph_prompt( ), helper.make_tensor_value_info( "present_value", - ORT_TYPE, + ort_type, [ config.batch_size, present_kv_seqlen if past_kv_format == Formats.BSNH else config.kv_num_heads, @@ -306,7 +317,7 @@ def create_group_query_attention_graph_prompt( ), helper.make_tensor_value_info( "present_key", - ORT_TYPE, + ort_type, [ config.batch_size, config.kv_sequence_length if past_kv_format == Formats.BSNH else config.kv_num_heads, @@ -316,7 +327,7 @@ def create_group_query_attention_graph_prompt( ), helper.make_tensor_value_info( "present_value", - ORT_TYPE, + ort_type, [ config.batch_size, config.kv_sequence_length if past_kv_format == Formats.BSNH else config.kv_num_heads, @@ -334,11 +345,13 @@ def create_group_query_attention_graph_prompt( ) model = helper.make_model(graph) + return model.SerializeToString() def create_group_query_attention_graph_past( config, + ort_type, past_kv_format=Formats.BSNH, share_buffer=True, local_window_size=-1, @@ -365,6 +378,8 @@ def create_group_query_attention_graph_past( "total_sequence_length", "cos_cache" if rotary else "", "sin_cache" if rotary else "", + "position_ids" if config.has_position_ids else "", + "attention_bias" if config.has_attention_bias else "", ], ["output", "present_key", "present_value"], "GroupQueryAttention_0", @@ -384,7 +399,7 @@ def create_group_query_attention_graph_past( graph_input = [ helper.make_tensor_value_info( "query", - ORT_TYPE, + ort_type, [ config.batch_size, config.sequence_length, @@ -397,7 +412,7 @@ def create_group_query_attention_graph_past( ), helper.make_tensor_value_info( "past_key", - ORT_TYPE, + ort_type, [ config.batch_size, past_kv_seqlen if past_kv_format == Formats.BSNH else config.kv_num_heads, @@ -407,7 +422,7 @@ def create_group_query_attention_graph_past( ), helper.make_tensor_value_info( "past_value", - ORT_TYPE, + ort_type, [ config.batch_size, past_kv_seqlen if past_kv_format == Formats.BSNH else config.kv_num_heads, @@ -430,7 +445,7 @@ def create_group_query_attention_graph_past( graph_input += [ helper.make_tensor_value_info( "key", - ORT_TYPE, + ort_type, [ config.batch_size, config.sequence_length, @@ -439,7 +454,7 @@ def create_group_query_attention_graph_past( ), helper.make_tensor_value_info( "value", - ORT_TYPE, + ort_type, [ config.batch_size, config.sequence_length, @@ -451,7 +466,7 @@ def create_group_query_attention_graph_past( graph_input += [ helper.make_tensor_value_info( "cos_cache", - ORT_TYPE, + ort_type, [ config.kv_sequence_length + (0 if share_buffer else config.sequence_length), (math.floor(config.head_size / 16) * 16) // 2, @@ -459,7 +474,7 @@ def create_group_query_attention_graph_past( ), helper.make_tensor_value_info( "sin_cache", - ORT_TYPE, + ort_type, [ config.kv_sequence_length + (0 if share_buffer else config.sequence_length), (math.floor(config.head_size / 16) * 16) // 2, @@ -467,15 +482,31 @@ def create_group_query_attention_graph_past( ), ] + if config.has_position_ids: + graph_input += [ + helper.make_tensor_value_info( + "position_ids", TensorProto.INT64, [config.batch_size, config.sequence_length] + ), + ] + + if config.has_attention_bias: + graph_input += [ + helper.make_tensor_value_info( + "attention_bias", + ort_type, + [config.batch_size, 1, config.sequence_length, present_kv_seqlen], + ), + ] + graph_output = [ helper.make_tensor_value_info( "output", - ORT_TYPE, + ort_type, [config.batch_size, config.sequence_length, config.num_heads * config.head_size], ), helper.make_tensor_value_info( "present_key", - ORT_TYPE, + ort_type, [ config.batch_size, present_kv_seqlen if past_kv_format == Formats.BSNH else config.kv_num_heads, @@ -485,7 +516,7 @@ def create_group_query_attention_graph_past( ), helper.make_tensor_value_info( "present_value", - ORT_TYPE, + ort_type, [ config.batch_size, present_kv_seqlen if past_kv_format == Formats.BSNH else config.kv_num_heads, @@ -639,7 +670,7 @@ def dk_pad_fn(dk_unpad): ) -def create_inputs(config: Config, kv_packed=False, qkv_packed=True): +def create_inputs(config: Config, torch_type, kv_packed=False, qkv_packed=True): qkv = torch.randn( config.batch_size, config.sequence_length, @@ -647,7 +678,7 @@ def create_inputs(config: Config, kv_packed=False, qkv_packed=True): config.num_heads, config.head_size, device="cpu", - dtype=TORCH_TYPE, + dtype=torch_type, requires_grad=False, ) key_padding_mask = generate_random_padding_mask( @@ -681,15 +712,20 @@ def gqa_prompt_func( cos=None, sin=None, seqlens_k=None, + position_ids=None, + attention_bias=None, window_size=-1, past_kv_format=Formats.BSNH, share_buffer=True, rotary_interleaved=False, softcap=0.0, use_smooth_softmax=False, + ort_type=TensorProto.FLOAT16, + numpy_type=numpy.float16, ): onnx_model_str = create_group_query_attention_graph_prompt( config, + ort_type, past_kv_format, share_buffer, local_window_size=window_size, @@ -699,9 +735,17 @@ def gqa_prompt_func( softcap=softcap, use_smooth_softmax=use_smooth_softmax, ) + q = torch.reshape(q, (config.batch_size, config.q_sequence_length, -1)) past_k = k.clone() if share_buffer else None past_v = v.clone() if share_buffer else None + + if config.has_position_ids: + assert position_ids is not None + + if config.has_attention_bias: + assert attention_bias is not None + if new_k is not None: new_k = torch.reshape(new_k, (config.batch_size, config.kv_sequence_length, -1)) new_v = torch.reshape(new_v, (config.batch_size, config.kv_sequence_length, -1)) @@ -713,6 +757,7 @@ def gqa_prompt_func( "seqlens_k": seqlens_k.detach().cpu().numpy().astype(numpy.int32), "total_sequence_length": torch.tensor([config.q_sequence_length], dtype=torch.int32).detach().cpu().numpy(), } + sess_options = SessionOptions() ort_session = InferenceSession(onnx_model_str, sess_options, providers=["CPUExecutionProvider"]) io_binding = ort_session.io_binding() @@ -726,15 +771,24 @@ def gqa_prompt_func( ort_inputs["sin_cache"] = sin.detach().cpu().numpy() io_binding.bind_cpu_input("cos_cache", ort_inputs["cos_cache"]) io_binding.bind_cpu_input("sin_cache", ort_inputs["sin_cache"]) + + if config.has_position_ids: + ort_inputs["position_ids"] = position_ids.detach().cpu().numpy() + io_binding.bind_cpu_input("position_ids", ort_inputs["position_ids"]) + + if config.has_attention_bias: + ort_inputs["attention_bias"] = attention_bias.detach().cpu().numpy() + io_binding.bind_cpu_input("attention_bias", ort_inputs["attention_bias"]) + io_binding.bind_cpu_input("query", ort_inputs["query"]) io_binding.bind_input( - "past_key", "cpu", 0, NUMPY_TYPE, ort_inputs["past_key"].shape(), ort_inputs["past_key"].data_ptr() + "past_key", "cpu", 0, numpy_type, ort_inputs["past_key"].shape(), ort_inputs["past_key"].data_ptr() ) io_binding.bind_input( "past_value", "cpu", 0, - NUMPY_TYPE, + numpy_type, ort_inputs["past_value"].shape(), ort_inputs["past_value"].data_ptr(), ) @@ -767,6 +821,15 @@ def gqa_prompt_func( ort_inputs["sin_cache"] = sin.detach().cpu().numpy() io_binding.bind_cpu_input("cos_cache", ort_inputs["cos_cache"]) io_binding.bind_cpu_input("sin_cache", ort_inputs["sin_cache"]) + + if config.has_position_ids: + ort_inputs["position_ids"] = position_ids.detach().cpu().numpy() + io_binding.bind_cpu_input("position_ids", ort_inputs["position_ids"]) + + if config.has_attention_bias: + ort_inputs["attention_bias"] = attention_bias.detach().cpu().numpy() + io_binding.bind_cpu_input("attention_bias", ort_inputs["attention_bias"]) + io_binding.bind_cpu_input("query", ort_inputs["query"]) io_binding.bind_cpu_input("seqlens_k", ort_inputs["seqlens_k"]) io_binding.bind_cpu_input("total_sequence_length", ort_inputs["total_sequence_length"]) @@ -790,16 +853,21 @@ def gqa_past_func( cos=None, sin=None, seqlens_k=None, + position_ids=None, + attention_bias=None, past_kv_format=Formats.BSNH, share_buffer=True, window_size=-1, rotary_interleaved=False, softcap=0.0, use_smooth_softmax=False, + ort_type=TensorProto.FLOAT16, + numpy_type=numpy.float16, ): assert seqlens_k is not None onnx_model_str = create_group_query_attention_graph_past( config, + ort_type, past_kv_format, share_buffer, local_window_size=window_size, @@ -812,6 +880,13 @@ def gqa_past_func( q = torch.reshape(q, (config.batch_size, config.sequence_length, -1)) past_k = k.clone() past_v = v.clone() + + if config.has_position_ids: + assert position_ids is not None + + if config.has_attention_bias: + assert attention_bias is not None + if new_k is not None: new_k = torch.reshape(new_k, (config.batch_size, config.sequence_length, -1)) new_v = torch.reshape(new_v, (config.batch_size, config.sequence_length, -1)) @@ -839,15 +914,24 @@ def gqa_past_func( ort_inputs["sin_cache"] = sin.detach().cpu().numpy() io_binding.bind_cpu_input("cos_cache", ort_inputs["cos_cache"]) io_binding.bind_cpu_input("sin_cache", ort_inputs["sin_cache"]) + + if config.has_position_ids: + ort_inputs["position_ids"] = position_ids.detach().cpu().numpy() + io_binding.bind_cpu_input("position_ids", ort_inputs["position_ids"]) + + if config.has_attention_bias: + ort_inputs["attention_bias"] = attention_bias.detach().cpu().numpy() + io_binding.bind_cpu_input("attention_bias", ort_inputs["attention_bias"]) + io_binding.bind_cpu_input("query", ort_inputs["query"]) io_binding.bind_input( - "past_key", "cpu", 0, NUMPY_TYPE, ort_inputs["past_key"].shape(), ort_inputs["past_key"].data_ptr() + "past_key", "cpu", 0, numpy_type, ort_inputs["past_key"].shape(), ort_inputs["past_key"].data_ptr() ) io_binding.bind_input( "past_value", "cpu", 0, - NUMPY_TYPE, + numpy_type, ort_inputs["past_value"].shape(), ort_inputs["past_value"].data_ptr(), ) @@ -887,6 +971,15 @@ def gqa_past_func( ort_inputs["sin_cache"] = sin.detach().cpu().numpy() io_binding.bind_cpu_input("cos_cache", ort_inputs["cos_cache"]) io_binding.bind_cpu_input("sin_cache", ort_inputs["sin_cache"]) + + if config.has_position_ids: + ort_inputs["position_ids"] = position_ids.detach().cpu().numpy() + io_binding.bind_cpu_input("position_ids", ort_inputs["position_ids"]) + + if config.has_attention_bias: + ort_inputs["attention_bias"] = attention_bias.detach().cpu().numpy() + io_binding.bind_cpu_input("attention_bias", ort_inputs["attention_bias"]) + io_binding.bind_cpu_input("query", ort_inputs["query"]) io_binding.bind_cpu_input("past_key", ort_inputs["past_key"]) io_binding.bind_cpu_input("past_value", ort_inputs["past_value"]) @@ -1056,8 +1149,48 @@ def attention_qkvpacked_ref( ) +def get_custom_attention_bias( + batch_size, sequence_length, total_seq_len, seqlens_k=None, past=False, torch_type=torch.float16 +): + if past: + assert seqlens_k is not None + attention_bias = torch.zeros((batch_size, 1, sequence_length, total_seq_len), dtype=torch_type) + for b in range(batch_size): + total_seq_len = seqlens_k[b] + 1 + past_seq_len = total_seq_len - sequence_length + + # Configure bias + for i in range(sequence_length): + for j in range(past_seq_len + i + 1, total_seq_len): + attention_bias[b][0][i][j] = -5000 + else: + attention_bias = torch.rand(batch_size, 1, sequence_length, total_seq_len, dtype=torch_type) + attention_bias = torch.triu(attention_bias, diagonal=1) + + return attention_bias + + +def get_custom_position_ids(batch_size, sequence_length, seqlens_k=None, past=False): + if past: + assert seqlens_k is not None + position_ids_data = [] + for b in range(batch_size): + total_seq_len = seqlens_k[b] + 1 + past_seq_len = total_seq_len - sequence_length + position_ids_data.append(list(range(past_seq_len, past_seq_len + sequence_length))) + + position_ids = torch.tensor(data=position_ids_data, dtype=torch.int64) + else: + position_ids = torch.zeros((batch_size, sequence_length), dtype=torch.int64) + + return position_ids + + def parity_check_gqa_prompt( config, + torch_type, + numpy_type, + ort_type, causal=True, local=False, past_format=Formats.BSNH, @@ -1075,7 +1208,7 @@ def parity_check_gqa_prompt( config.num_heads, config.head_size, device="cpu", - dtype=TORCH_TYPE, + dtype=torch_type, requires_grad=False, ) k = torch.randn( @@ -1084,7 +1217,7 @@ def parity_check_gqa_prompt( config.kv_num_heads if past_format == Formats.BSNH else config.buffer_sequence_length, config.head_size, device="cpu", - dtype=TORCH_TYPE, + dtype=torch_type, requires_grad=False, ) v = torch.randn( @@ -1093,7 +1226,7 @@ def parity_check_gqa_prompt( config.kv_num_heads if past_format == Formats.BSNH else config.buffer_sequence_length, config.head_size, device="cpu", - dtype=TORCH_TYPE, + dtype=torch_type, requires_grad=False, ) new_k = torch.randn( @@ -1102,7 +1235,7 @@ def parity_check_gqa_prompt( config.kv_num_heads, config.head_size, device="cpu", - dtype=TORCH_TYPE, + dtype=torch_type, requires_grad=False, ) new_v = torch.randn( @@ -1111,7 +1244,7 @@ def parity_check_gqa_prompt( config.kv_num_heads, config.head_size, device="cpu", - dtype=TORCH_TYPE, + dtype=torch_type, requires_grad=False, ) @@ -1137,8 +1270,8 @@ def parity_check_gqa_prompt( rotary_fraction = 1.0 rotary_dim = math.floor(int(rotary_fraction * config.head_size) / 16) * 16 angle = torch.rand(config.buffer_sequence_length, rotary_dim // 2, device="cpu") * 2 * math.pi - cos = torch.cos(angle).to(dtype=TORCH_TYPE) - sin = torch.sin(angle).to(dtype=TORCH_TYPE) + cos = torch.cos(angle).to(dtype=torch_type) + sin = torch.sin(angle).to(dtype=torch_type) rot = LlamaMSRotaryEmbedding() q_ro = rot( q.clone(), cos.unsqueeze(0).unsqueeze(2), sin.unsqueeze(0).unsqueeze(2), rotary_seqlens, rotary_interleaved @@ -1154,14 +1287,31 @@ def parity_check_gqa_prompt( cos, sin = None, None q_ro, k_ro = q, new_k - rearrange(torch.arange(config.kv_sequence_length, device="cpu"), "s -> 1 s") + position_ids = ( + get_custom_position_ids(config.batch_size, config.kv_sequence_length, seqlens_k=None, past=False) + if config.has_position_ids + else None + ) + attention_bias = ( + get_custom_attention_bias( + config.batch_size, + config.kv_sequence_length, + config.q_sequence_length, + seqlens_k=None, + past=False, + torch_type=torch_type, + ) + if config.has_attention_bias + else None + ) + arange = rearrange(torch.arange(config.buffer_sequence_length, device="cpu"), "s -> 1 s") cache_seqlens_expanded = rearrange(cache_seqlens, "b -> b 1") kv_seqlens = torch.tensor([config.kv_sequence_length], device="cpu").repeat(config.batch_size) kv_seqlens_expanded = rearrange(kv_seqlens, "b -> b 1") update_mask = arange < kv_seqlens_expanded - k_cache_ref[update_mask] = rearrange(k_ro, "b s ... -> (b s) ...").to(dtype=TORCH_TYPE) - v_cache_ref[update_mask] = rearrange(new_v, "b s ... -> (b s) ...").to(dtype=TORCH_TYPE) + k_cache_ref[update_mask] = rearrange(k_ro, "b s ... -> (b s) ...").to(dtype=torch_type) + v_cache_ref[update_mask] = rearrange(new_v, "b s ... -> (b s) ...").to(dtype=torch_type) k_cache_rep = repeat(k_cache_ref, "b s h d -> b s (h g) d", g=config.num_heads // config.kv_num_heads) v_cache_rep = repeat(v_cache_ref, "b s h d -> b s (h g) d", g=config.num_heads // config.kv_num_heads) key_padding_mask = arange < cache_seqlens_expanded @@ -1184,6 +1334,7 @@ def parity_check_gqa_prompt( v_cache_ref = v_cache_ref.transpose(1, 2) # Flash function + # Cache seqlens is reduced by 1 since it is required to be past_seq_len + seq_len - 1 if packed: packed_qkv = torch.concatenate([q, new_k, new_v], dim=2) out, present_k, present_v = gqa_prompt_func( @@ -1195,13 +1346,17 @@ def parity_check_gqa_prompt( None, cos, sin, - cache_seqlens, + cache_seqlens - 1, + position_ids, + attention_bias, left_window_size, past_format, True, rotary_interleaved, softcap, use_smooth_softmax=use_smooth_softmax, + ort_type=ort_type, + numpy_type=numpy_type, ) else: out, present_k, present_v = gqa_prompt_func( @@ -1213,24 +1368,28 @@ def parity_check_gqa_prompt( new_v, cos, sin, - cache_seqlens, + cache_seqlens - 1, + position_ids, + attention_bias, left_window_size, past_format, True, rotary_interleaved, softcap, use_smooth_softmax=use_smooth_softmax, + ort_type=ort_type, + numpy_type=numpy_type, ) out = torch.squeeze(out, 0) out = torch.reshape(out, (config.batch_size, config.q_sequence_length, config.num_heads, config.head_size)) out = out.detach().cpu().numpy() # Make sure past-present buffer updating correctly - assert numpy.allclose(present_k, k_cache_ref.detach().cpu().numpy(), rtol=RTOL, atol=ATOL, equal_nan=True) - assert numpy.allclose(present_v, v_cache_ref.detach().cpu().numpy(), rtol=RTOL, atol=ATOL, equal_nan=True) + assert numpy.allclose(present_k, k_cache_ref.detach().cpu().numpy(), rtol=rtol, atol=atol, equal_nan=True) + assert numpy.allclose(present_v, v_cache_ref.detach().cpu().numpy(), rtol=rtol, atol=atol, equal_nan=True) # Compare results - all_close = numpy.allclose(out, out_ref, rtol=RTOL, atol=ATOL, equal_nan=True) + all_close = numpy.allclose(out, out_ref, rtol=rtol, atol=atol, equal_nan=True) correct = GREEN + "True" + RESET if all_close else RED + "False" + RESET print( "KV-buffer", @@ -1262,6 +1421,10 @@ def parity_check_gqa_prompt( config.kv_num_heads, " h:", config.head_size, + " has_position_ids:", + config.has_position_ids, + " has_attention_bias:", + config.has_attention_bias, " Mean Error:", numpy.mean(numpy.abs(out - out_ref)), correct, @@ -1271,6 +1434,9 @@ def parity_check_gqa_prompt( def parity_check_gqa_prompt_no_buff( config, + torch_type, + numpy_type, + ort_type, causal=True, local=False, past_format=Formats.BSNH, @@ -1288,7 +1454,7 @@ def parity_check_gqa_prompt_no_buff( config.num_heads, config.head_size, device="cpu", - dtype=TORCH_TYPE, + dtype=torch_type, requires_grad=False, ) new_k = torch.randn( @@ -1297,7 +1463,7 @@ def parity_check_gqa_prompt_no_buff( config.kv_num_heads, config.head_size, device="cpu", - dtype=TORCH_TYPE, + dtype=torch_type, requires_grad=False, ) new_v = torch.randn( @@ -1306,7 +1472,7 @@ def parity_check_gqa_prompt_no_buff( config.kv_num_heads, config.head_size, device="cpu", - dtype=TORCH_TYPE, + dtype=torch_type, requires_grad=False, ) @@ -1329,8 +1495,8 @@ def parity_check_gqa_prompt_no_buff( rotary_fraction = 1.0 rotary_dim = math.floor(int(rotary_fraction * config.head_size) / 16) * 16 angle = torch.rand(config.kv_sequence_length, rotary_dim // 2, device="cpu") * 2 * math.pi - cos = torch.cos(angle).to(dtype=TORCH_TYPE) - sin = torch.sin(angle).to(dtype=TORCH_TYPE) + cos = torch.cos(angle).to(dtype=torch_type) + sin = torch.sin(angle).to(dtype=torch_type) rot = LlamaMSRotaryEmbedding() q_ro = rot( q.clone(), cos.unsqueeze(0).unsqueeze(2), sin.unsqueeze(0).unsqueeze(2), rotary_seqlens, rotary_interleaved @@ -1347,6 +1513,24 @@ def parity_check_gqa_prompt_no_buff( q_ro, k_ro = q, k_cache_ref k_cache_ref = k_ro + position_ids = ( + get_custom_position_ids(config.batch_size, config.kv_sequence_length, seqlens_k=None, past=False) + if config.has_position_ids + else None + ) + attention_bias = ( + get_custom_attention_bias( + config.batch_size, + config.kv_sequence_length, + config.q_sequence_length, + seqlens_k=None, + past=False, + torch_type=torch_type, + ) + if config.has_attention_bias + else None + ) + brange = rearrange(torch.arange(config.kv_sequence_length, device="cpu"), "s -> 1 s") cache_seqlens_expanded = rearrange(cache_seqlens, "b -> b 1") new_mask = brange < cache_seqlens_expanded @@ -1371,6 +1555,7 @@ def parity_check_gqa_prompt_no_buff( v_cache_ref = v_cache_ref.transpose(1, 2) # Flash function + # Cache seqlens is reduced by 1 since it is required to be past_seq_len + seq_len - 1 if packed: packed_qkv = torch.concatenate([q, new_k, new_v], dim=2) out, present_k, present_v = gqa_prompt_func( @@ -1383,12 +1568,16 @@ def parity_check_gqa_prompt_no_buff( cos, sin, cache_seqlens - 1, + position_ids, + attention_bias, left_window_size, past_format, False, rotary_interleaved, softcap, use_smooth_softmax=use_smooth_softmax, + ort_type=ort_type, + numpy_type=numpy_type, ) else: out, present_k, present_v = gqa_prompt_func( @@ -1401,23 +1590,27 @@ def parity_check_gqa_prompt_no_buff( cos, sin, cache_seqlens - 1, + position_ids, + attention_bias, left_window_size, past_format, False, rotary_interleaved, softcap, use_smooth_softmax=use_smooth_softmax, + ort_type=ort_type, + numpy_type=numpy_type, ) out = torch.squeeze(out, 0) out = torch.reshape(out, (config.batch_size, config.q_sequence_length, config.num_heads, config.head_size)) out = out.detach().cpu().numpy() # Make sure past-present buffer updating correctly - assert numpy.allclose(present_k, k_cache_ref.detach().cpu().numpy(), rtol=RTOL, atol=ATOL, equal_nan=True) - assert numpy.allclose(present_v, v_cache_ref.detach().cpu().numpy(), rtol=RTOL, atol=ATOL, equal_nan=True) + assert numpy.allclose(present_k, k_cache_ref.detach().cpu().numpy(), rtol=rtol, atol=atol, equal_nan=True) + assert numpy.allclose(present_v, v_cache_ref.detach().cpu().numpy(), rtol=rtol, atol=atol, equal_nan=True) # Compare results - all_close = numpy.allclose(out, out_ref, rtol=RTOL, atol=ATOL, equal_nan=True) + all_close = numpy.allclose(out, out_ref, rtol=rtol, atol=atol, equal_nan=True) correct = GREEN + "True" + RESET if all_close else RED + "False" + RESET print( "No buff", @@ -1449,6 +1642,10 @@ def parity_check_gqa_prompt_no_buff( config.kv_num_heads, " h:", config.head_size, + " has_position_ids:", + config.has_position_ids, + " has_attention_bias:", + config.has_attention_bias, " Mean Error:", numpy.mean(numpy.abs(out - out_ref)), correct, @@ -1458,6 +1655,9 @@ def parity_check_gqa_prompt_no_buff( def parity_check_gqa_past( config, + torch_type, + numpy_type, + ort_type, causal=True, local=False, past_format=Formats.BSNH, @@ -1475,7 +1675,7 @@ def parity_check_gqa_past( config.num_heads, config.head_size, device="cpu", - dtype=TORCH_TYPE, + dtype=torch_type, requires_grad=False, ) k = torch.randn( @@ -1484,7 +1684,7 @@ def parity_check_gqa_past( config.kv_num_heads if past_format == Formats.BSNH else config.kv_sequence_length, config.head_size, device="cpu", - dtype=TORCH_TYPE, + dtype=torch_type, requires_grad=False, ) v = torch.randn( @@ -1493,7 +1693,7 @@ def parity_check_gqa_past( config.kv_num_heads if past_format == Formats.BSNH else config.kv_sequence_length, config.head_size, device="cpu", - dtype=TORCH_TYPE, + dtype=torch_type, requires_grad=False, ) new_k = torch.randn( @@ -1502,7 +1702,7 @@ def parity_check_gqa_past( config.kv_num_heads, config.head_size, device="cpu", - dtype=TORCH_TYPE, + dtype=torch_type, requires_grad=False, ) new_v = torch.randn( @@ -1511,7 +1711,7 @@ def parity_check_gqa_past( config.kv_num_heads, config.head_size, device="cpu", - dtype=TORCH_TYPE, + dtype=torch_type, requires_grad=False, ) @@ -1542,8 +1742,8 @@ def parity_check_gqa_past( rotary_fraction = 1.0 rotary_dim = math.floor(int(rotary_fraction * config.head_size) / 16) * 16 angle = torch.rand(config.kv_sequence_length, rotary_dim // 2, device="cpu") * 2 * math.pi - cos = torch.cos(angle).to(dtype=TORCH_TYPE) - sin = torch.sin(angle).to(dtype=TORCH_TYPE) + cos = torch.cos(angle).to(dtype=torch_type) + sin = torch.sin(angle).to(dtype=torch_type) rot = LlamaMSRotaryEmbedding() q_ro = rot( q.clone(), cos.unsqueeze(0).unsqueeze(2), sin.unsqueeze(0).unsqueeze(2), cache_seqlens, rotary_interleaved @@ -1564,8 +1764,8 @@ def parity_check_gqa_past( update_mask = torch.logical_and( cache_seqlens_expanded <= arange, arange < cache_seqlens_expanded + config.sequence_length ) - k_cache_ref[update_mask] = rearrange(k_ro, "b s ... -> (b s) ...") - v_cache_ref[update_mask] = rearrange(new_v, "b s ... -> (b s) ...") + k_cache_ref[update_mask] = rearrange(k_ro, "b s ... -> (b s) ...").to(dtype=torch_type) + v_cache_ref[update_mask] = rearrange(new_v, "b s ... -> (b s) ...").to(dtype=torch_type) k_cache_rep = repeat(k_cache_ref, "b s h d -> b s (h g) d", g=config.num_heads // config.kv_num_heads) v_cache_rep = repeat(v_cache_ref, "b s h d -> b s (h g) d", g=config.num_heads // config.kv_num_heads) key_padding_mask = arange < cache_seqlens_expanded + config.sequence_length @@ -1589,6 +1789,24 @@ def parity_check_gqa_past( cache_seqlens += config.sequence_length - 1 + position_ids = ( + get_custom_position_ids(config.batch_size, config.sequence_length, seqlens_k=cache_seqlens, past=True) + if config.has_position_ids + else None + ) + attention_bias = ( + get_custom_attention_bias( + config.batch_size, + config.sequence_length, + config.kv_sequence_length, + seqlens_k=cache_seqlens, + past=True, + torch_type=torch_type, + ) + if config.has_attention_bias + else None + ) + # ORT function if packed: packed_qkv = torch.concatenate([q, new_k, new_v], dim=2) @@ -1602,12 +1820,16 @@ def parity_check_gqa_past( cos, sin, cache_seqlens, + position_ids, + attention_bias, past_format, True, left_window_size, rotary_interleaved, softcap, use_smooth_softmax=use_smooth_softmax, + ort_type=ort_type, + numpy_type=numpy_type, ) else: out, present_k, present_v = gqa_past_func( @@ -1620,23 +1842,27 @@ def parity_check_gqa_past( cos, sin, cache_seqlens, + position_ids, + attention_bias, past_format, True, left_window_size, rotary_interleaved, softcap, use_smooth_softmax=use_smooth_softmax, + ort_type=ort_type, + numpy_type=numpy_type, ) out = torch.squeeze(out, 0) out = torch.reshape(out, (config.batch_size, config.sequence_length, config.num_heads, config.head_size)) out = out.detach().cpu().numpy() # Make sure past-present buffer updating correctly - assert numpy.allclose(present_k, k_cache_ref.detach().cpu().numpy(), rtol=RTOL, atol=ATOL, equal_nan=True) - assert numpy.allclose(present_v, v_cache_ref.detach().cpu().numpy(), rtol=RTOL, atol=ATOL, equal_nan=True) + assert numpy.allclose(present_k, k_cache_ref.detach().cpu().numpy(), rtol=rtol, atol=atol, equal_nan=True) + assert numpy.allclose(present_v, v_cache_ref.detach().cpu().numpy(), rtol=rtol, atol=atol, equal_nan=True) # Compare results - all_close = numpy.allclose(out, out_ref, rtol=RTOL, atol=ATOL, equal_nan=True) + all_close = numpy.allclose(out, out_ref, rtol=rtol, atol=atol, equal_nan=True) correct = GREEN + "True" + RESET if all_close else RED + "False" + RESET print( "KV-buffer", @@ -1668,6 +1894,10 @@ def parity_check_gqa_past( config.kv_num_heads, " h:", config.head_size, + " has_position_ids:", + config.has_position_ids, + " has_attention_bias:", + config.has_attention_bias, " Mean Error:", numpy.mean(numpy.abs(out - out_ref)), correct, @@ -1677,6 +1907,9 @@ def parity_check_gqa_past( def parity_check_gqa_past_no_buff( config, + torch_type, + numpy_type, + ort_type, causal=True, local=False, past_format=Formats.BSNH, @@ -1695,7 +1928,7 @@ def parity_check_gqa_past_no_buff( config.num_heads, config.head_size, device="cpu", - dtype=TORCH_TYPE, + dtype=torch_type, requires_grad=False, ) k = torch.randn( @@ -1704,7 +1937,7 @@ def parity_check_gqa_past_no_buff( config.kv_num_heads if past_format == Formats.BSNH else config.kv_sequence_length, config.head_size, device="cpu", - dtype=TORCH_TYPE, + dtype=torch_type, requires_grad=False, ) v = torch.randn( @@ -1713,7 +1946,7 @@ def parity_check_gqa_past_no_buff( config.kv_num_heads if past_format == Formats.BSNH else config.kv_sequence_length, config.head_size, device="cpu", - dtype=TORCH_TYPE, + dtype=torch_type, requires_grad=False, ) new_k = torch.randn( @@ -1722,7 +1955,7 @@ def parity_check_gqa_past_no_buff( config.kv_num_heads, config.head_size, device="cpu", - dtype=TORCH_TYPE, + dtype=torch_type, requires_grad=False, ) new_v = torch.randn( @@ -1731,7 +1964,7 @@ def parity_check_gqa_past_no_buff( config.kv_num_heads, config.head_size, device="cpu", - dtype=TORCH_TYPE, + dtype=torch_type, requires_grad=False, ) @@ -1767,8 +2000,8 @@ def parity_check_gqa_past_no_buff( angle = ( torch.rand(config.kv_sequence_length + config.sequence_length, rotary_dim // 2, device="cpu") * 2 * math.pi ) - cos = torch.cos(angle).to(dtype=TORCH_TYPE) - sin = torch.sin(angle).to(dtype=TORCH_TYPE) + cos = torch.cos(angle).to(dtype=torch_type) + sin = torch.sin(angle).to(dtype=torch_type) rot = LlamaMSRotaryEmbedding() q_ro = rot( q.clone(), cos.unsqueeze(0).unsqueeze(2), sin.unsqueeze(0).unsqueeze(2), cache_seqlens, rotary_interleaved @@ -1789,8 +2022,8 @@ def parity_check_gqa_past_no_buff( update_mask = torch.logical_and( cache_seqlens_expanded <= arange, arange < cache_seqlens_expanded + config.sequence_length ) - k_cache_ref[update_mask] = rearrange(k_ro, "b s ... -> (b s) ...") - v_cache_ref[update_mask] = rearrange(new_v, "b s ... -> (b s) ...") + k_cache_ref[update_mask] = rearrange(k_ro, "b s ... -> (b s) ...").to(dtype=torch_type) + v_cache_ref[update_mask] = rearrange(new_v, "b s ... -> (b s) ...").to(dtype=torch_type) k_cache_rep = repeat(k_cache_ref, "b s h d -> b s (h g) d", g=config.num_heads // config.kv_num_heads) v_cache_rep = repeat(v_cache_ref, "b s h d -> b s (h g) d", g=config.num_heads // config.kv_num_heads) key_padding_mask = arange < cache_seqlens_expanded + config.sequence_length @@ -1814,6 +2047,24 @@ def parity_check_gqa_past_no_buff( cache_seqlens += config.sequence_length - 1 + position_ids = ( + get_custom_position_ids(config.batch_size, config.sequence_length, seqlens_k=cache_seqlens, past=True) + if config.has_position_ids + else None + ) + attention_bias = ( + get_custom_attention_bias( + config.batch_size, + config.sequence_length, + config.kv_sequence_length + config.sequence_length, + seqlens_k=cache_seqlens, + past=True, + torch_type=torch_type, + ) + if config.has_attention_bias + else None + ) + # Flash function if packed: packed_qkv = torch.concatenate([q, new_k, new_v], dim=2) @@ -1827,12 +2078,16 @@ def parity_check_gqa_past_no_buff( cos, sin, cache_seqlens, + position_ids, + attention_bias, past_format, False, window_size=left_window_size, rotary_interleaved=rotary_interleaved, softcap=softcap, use_smooth_softmax=use_smooth_softmax, + ort_type=ort_type, + numpy_type=numpy_type, ) else: out, present_k, present_v = gqa_past_func( @@ -1845,19 +2100,23 @@ def parity_check_gqa_past_no_buff( cos, sin, cache_seqlens, + position_ids, + attention_bias, past_format, False, window_size=left_window_size, rotary_interleaved=rotary_interleaved, softcap=softcap, use_smooth_softmax=use_smooth_softmax, + ort_type=ort_type, + numpy_type=numpy_type, ) out = torch.squeeze(out, 0) out = torch.reshape(out, (config.batch_size, config.sequence_length, config.num_heads, config.head_size)) out = out.detach().cpu().numpy() # Compare results - all_close = numpy.allclose(out, out_ref, rtol=RTOL, atol=ATOL, equal_nan=True) + all_close = numpy.allclose(out, out_ref, rtol=rtol, atol=atol, equal_nan=True) correct = GREEN + "True" + RESET if all_close else RED + "False" + RESET print( "NO buff", @@ -1889,6 +2148,10 @@ def parity_check_gqa_past_no_buff( config.kv_num_heads, " h:", config.head_size, + " has_position_ids:", + config.has_position_ids, + " has_attention_bias:", + config.has_attention_bias, " Mean Error:", numpy.mean(numpy.abs(out - out_ref)), correct, @@ -1897,60 +2160,98 @@ def parity_check_gqa_past_no_buff( class TestGQA(unittest.TestCase): - def test_gqa_no_past(self): + def setUp(self): + # Define precision configurations + self.precision_configs = [ + { + "ort_type": TensorProto.FLOAT16, + "torch_type": torch.float16, + "numpy_type": numpy.float16, + "rtol": 1e-2, + "atol": 1e-2, + }, + { + "ort_type": TensorProto.FLOAT, + "torch_type": torch.float32, + "numpy_type": numpy.float32, + "rtol": 1e-5, + "atol": 1e-5, + }, + ] + + def run_test_config( + self, test_func, config_class, batches, seqs, num_h, h_sizes, pos_ids_attn_bias, additional_params=None + ): + if additional_params is None: + additional_params = {} + + random.seed(69) torch.manual_seed(69) + + for precision in self.precision_configs: + print( + f"\nRunning tests with precision: {'FLOAT16' if precision['ort_type'] == TensorProto.FLOAT16 else 'FLOAT32'}" + ) + for b in batches: + for s, s2 in seqs: + for n, n2 in num_h: + for h in h_sizes: + for local in [False, True]: + for rotary, rotary_interleaved in [(False, False), (True, False), (True, True)]: + for packed in [False, True]: + for softcap in [0.0, 50.0]: + for use_smooth_softmax in [False, True]: + for has_pos, has_attn in pos_ids_attn_bias: + if config_class == PromptConfig: + config = config_class( + b, s, s2, s + s2 + 8, n, n2, h, has_pos, has_attn + ) + else: # Config + sp = random.randint(1, s2 - s) if s2 - s > 0 else 0 + config = config_class(b, s, s2, sp, n, n2, h, has_pos, has_attn) + + params = { + "config": config, + "torch_type": precision["torch_type"], + "numpy_type": precision["numpy_type"], + "ort_type": precision["ort_type"], + "rtol": precision["rtol"], + "atol": precision["atol"], + "local": local, + "past_format": Formats.BNSH, + "rotary": rotary, + "rotary_interleaved": rotary_interleaved, + "packed": packed, + "softcap": softcap, + "use_smooth_softmax": use_smooth_softmax, + } + params.update(additional_params) + + all_close = test_func(**params) + self.assertTrue(all_close) + + def test_gqa_no_past(self): print("-------- TEST GQA NO PAST (PROMPT CASE) ---------") batches = [3] if pipeline_mode else [1, 3, 5] seqs = ( - [ - (127, 127), - (240, 240), - ] + [(127, 127), (240, 240)] + if pipeline_mode + else [(127, 127), (35, 35), (2000, 2000), (200, 200), (240, 240), (8000, 8000)] + ) + pos_ids_attn_bias = ( + [(False, False), (True, True)] if pipeline_mode - else [ - (127, 127), - (35, 35), - (2000, 2000), - (200, 200), - (240, 240), - (8000, 8000), - ] + else [(False, False), (True, True), (False, True), (True, False)] ) num_h = [(32, 8)] if pipeline_mode else [(6, 6), (6, 3), (9, 9), (9, 3)] h_sizes = [128] if pipeline_mode else [32, 40, 64, 80, 96, 128, 160, 192, 224, 256] - for b in batches: - for sq, skv in seqs: - for n, n2 in num_h: - for h in h_sizes: - for local in [False, True]: - for rotary, rotary_interleaved in [(False, False), (True, False), (True, True)]: - for packed in [False, True]: - for softcap in [0.0, 50.0]: - for use_smooth_softmax in [False, True]: - config = PromptConfig(b, sq, skv, sq + skv + 8, n, n2, h) - past_kv_format = Formats.BNSH - all_close = parity_check_gqa_prompt( - config, - local=local, - past_format=past_kv_format, - rotary=rotary, - rotary_interleaved=rotary_interleaved, - packed=packed, - softcap=softcap, - use_smooth_softmax=use_smooth_softmax, - ) - self.assertTrue(all_close) - all_close = parity_check_gqa_prompt_no_buff( - config, - local=local, - past_format=past_kv_format, - rotary=rotary, - rotary_interleaved=rotary_interleaved, - packed=packed, - softcap=softcap, - use_smooth_softmax=use_smooth_softmax, - ) - self.assertTrue(all_close) + + # Test with buffer + self.run_test_config(parity_check_gqa_prompt, PromptConfig, batches, seqs, num_h, h_sizes, pos_ids_attn_bias) + # Test without buffer + self.run_test_config( + parity_check_gqa_prompt_no_buff, PromptConfig, batches, seqs, num_h, h_sizes, pos_ids_attn_bias + ) def test_gqa_past(self): print("-------- TEST GQA PAST (TOKEN GEN) ---------") @@ -1958,61 +2259,20 @@ def test_gqa_past(self): seqs = ( [(1, 128)] if pipeline_mode - else [ - (1, 128), - (1, 339), - (1, 1024), - (1, 5000), - (1, 800), - (1, 256), - (1, 799), - (1, 2048), - # (1, 128 * 512), - # (16, 128 * 512), - # (128, 128), - ] + else [(1, 128), (1, 339), (1, 1024), (1, 5000), (1, 800), (1, 256), (1, 799), (1, 2048)] + ) + pos_ids_attn_bias = ( + [(False, False), (True, True)] + if pipeline_mode + else [(False, False), (True, True), (False, True), (True, False)] ) num_h = [(9, 3)] if pipeline_mode else [(6, 6), (6, 3), (9, 9), (9, 3)] h_sizes = [64] if pipeline_mode else [32, 40, 64, 80, 96, 128, 160, 192, 224, 256] - random.seed(69) - for b in batches: - for s, s2 in seqs: - for n, n2 in num_h: - for h in h_sizes: - for local in [False, True]: - for rotary, rotary_interleaved in [(False, False), (True, False), (True, True)]: - for packed in [False, True]: - for softcap in [0.0, 50.0]: - for use_smooth_softmax in [False, True]: - sp = random.randint(1, s2 - s) if s2 - s > 0 else 0 - config = Config(b, s, s2, sp, n, n2, h) - past_kv_format = Formats.BNSH - all_close = parity_check_gqa_past( - config, - local=local, - past_format=past_kv_format, - rtol=RTOL, - atol=ATOL, - rotary=rotary, - rotary_interleaved=rotary_interleaved, - packed=packed, - softcap=softcap, - use_smooth_softmax=use_smooth_softmax, - ) - self.assertTrue(all_close) - all_close = parity_check_gqa_past_no_buff( - config, - local=local, - past_format=past_kv_format, - rtol=RTOL, - atol=ATOL, - rotary=rotary, - rotary_interleaved=rotary_interleaved, - packed=packed, - softcap=softcap, - use_smooth_softmax=use_smooth_softmax, - ) - self.assertTrue(all_close) + + # Test with buffer + self.run_test_config(parity_check_gqa_past, Config, batches, seqs, num_h, h_sizes, pos_ids_attn_bias) + # Test without buffer + self.run_test_config(parity_check_gqa_past_no_buff, Config, batches, seqs, num_h, h_sizes, pos_ids_attn_bias) def test_gqa_interactive_one_batch(self): print("-------- TEST GQA INTERACTIVE ---------") @@ -2020,54 +2280,37 @@ def test_gqa_interactive_one_batch(self): seqs = ( [(256, 2048)] if pipeline_mode - else [ - (1, 128), - (1, 339), - (1, 1024), - (1, 5000), - (1, 800), - (1, 256), - (1, 799), - (1, 2048), - # (1, 128 * 512), - # (16, 128 * 512), - # (128, 128), - ] + else [(1, 128), (1, 339), (1, 1024), (1, 5000), (1, 800), (1, 256), (1, 799), (1, 2048)] + ) + pos_ids_attn_bias = ( + [(False, False), (True, True)] + if pipeline_mode + else [(False, False), (True, True), (False, True), (True, False)] ) num_h = [(32, 8)] if pipeline_mode else [(6, 6), (6, 3), (9, 9), (9, 3)] h_sizes = [32] if pipeline_mode else [32, 40, 64, 80, 96, 128, 160, 192, 224, 256] - random.seed(69) - for b in batches: - for s, s2 in seqs: - for n, n2 in num_h: - for h in h_sizes: - for local in [False, True]: - for rotary, rotary_interleaved in [(False, False), (True, False), (True, True)]: - for packed in [False, True]: - config = Config(b, s, s2, -1, n, n2, h) - past_kv_format = Formats.BNSH - all_close = parity_check_gqa_past( - config, - local=local, - past_format=past_kv_format, - rtol=RTOL, - atol=ATOL, - rotary=rotary, - rotary_interleaved=rotary_interleaved, - packed=packed, - ) - self.assertTrue(all_close) - all_close = parity_check_gqa_past_no_buff( - config, - local=local, - past_format=past_kv_format, - rtol=RTOL, - atol=ATOL, - rotary=rotary, - rotary_interleaved=rotary_interleaved, - packed=packed, - ) - self.assertTrue(all_close) + + # Only test softcap=0.0 for interactive case as per original + self.run_test_config( + parity_check_gqa_past, + Config, + batches, + seqs, + num_h, + h_sizes, + pos_ids_attn_bias, + additional_params={"softcap": 0.0, "use_smooth_softmax": False}, + ) + self.run_test_config( + parity_check_gqa_past_no_buff, + Config, + batches, + seqs, + num_h, + h_sizes, + pos_ids_attn_bias, + additional_params={"softcap": 0.0, "use_smooth_softmax": False}, + ) if __name__ == "__main__": diff --git a/onnxruntime/test/python/transformers/test_flash_attn_cuda.py b/onnxruntime/test/python/transformers/test_gqa_cuda.py similarity index 79% rename from onnxruntime/test/python/transformers/test_flash_attn_cuda.py rename to onnxruntime/test/python/transformers/test_gqa_cuda.py index a74d5389e9047..3923b229a0bff 100644 --- a/onnxruntime/test/python/transformers/test_flash_attn_cuda.py +++ b/onnxruntime/test/python/transformers/test_gqa_cuda.py @@ -17,7 +17,6 @@ import numpy import torch -from bert_padding import pad_input, unpad_input from einops import rearrange, repeat from onnx import TensorProto, helper from packaging import version @@ -39,20 +38,16 @@ class Formats: class Config: batch_size = 0 sequence_length = 0 - kv_sequence_length = 0 - past_sequence_length = 0 + kv_sequence_length = 0 # this is past sequence length when there is past state. num_heads = 0 kv_num_heads = 0 head_size = 0 ep = "CUDAExecutionProvider" - def __init__( - self, batch_size, sequence_length, kv_sequence_length, past_sequence_length, num_heads, kv_num_heads, head_size - ): + def __init__(self, batch_size, sequence_length, kv_sequence_length, num_heads, kv_num_heads, head_size): self.batch_size = batch_size self.sequence_length = sequence_length self.kv_sequence_length = kv_sequence_length - self.past_sequence_length = past_sequence_length self.num_heads = num_heads self.kv_num_heads = kv_num_heads self.head_size = head_size @@ -61,7 +56,7 @@ def __repr__(self): short_ep = self.ep[: -len("ExecutionProvider")].lower() return ( f"Config(batch_size={self.batch_size}, sequence_length={self.sequence_length}, " - f"kv_sequence_length={self.kv_sequence_length}, past_sequence_length={self.past_sequence_length}, " + f"kv_sequence_length={self.kv_sequence_length}, " f"num_heads={self.num_heads}, kv_num_heads={self.kv_num_heads}, head_size={self.head_size}, ep={short_ep})" ) @@ -103,118 +98,6 @@ def __repr__(self): ) -def create_packed_multihead_attention_graph(config): - nodes = [ - helper.make_node( - "PackedMultiHeadAttention", - [ - "query", - "", - "", - "", - "token_offset", - "cumulative_sequence_length", - ], - ["output"], - "PackedMultiHeadAttention_0", - num_heads=config.num_heads, - domain="com.microsoft", - ), - ] - - graph = helper.make_graph( - nodes, - "PackedMultiHeadAttention_Graph", - [ - helper.make_tensor_value_info( - "query", - TensorProto.FLOAT16, - [ - -1, - config.num_heads, - 3, - config.head_size, - ], - ), - helper.make_tensor_value_info( - "token_offset", TensorProto.INT32, [config.batch_size, config.sequence_length] - ), - helper.make_tensor_value_info("cumulative_sequence_length", TensorProto.INT32, [config.batch_size + 1]), - ], - [ - helper.make_tensor_value_info( - "output", - TensorProto.FLOAT16, - [-1, config.num_heads * config.head_size], - ), - ], - ) - - model = helper.make_model(graph) - return model.SerializeToString() - - -def create_multihead_attention_graph(config): - nodes = [ - helper.make_node( - "MultiHeadAttention", - [ - "query", - "key", - "value", - ], - ["output"], - "MultiHeadAttention_0", - num_heads=config.num_heads, - domain="com.microsoft", - ), - ] - - graph = helper.make_graph( - nodes, - "MultiHeadAttention_Graph", - [ - helper.make_tensor_value_info( - "query", - TensorProto.FLOAT16, - [ - config.batch_size, - config.sequence_length, - config.num_heads * config.head_size, - ], - ), - helper.make_tensor_value_info( - "key", - TensorProto.FLOAT16, - [ - config.batch_size, - config.kv_sequence_length, - config.num_heads * config.head_size, - ], - ), - helper.make_tensor_value_info( - "value", - TensorProto.FLOAT16, - [ - config.batch_size, - config.kv_sequence_length, - config.num_heads * config.head_size, - ], - ), - ], - [ - helper.make_tensor_value_info( - "output", - TensorProto.FLOAT16, - [config.batch_size, config.sequence_length, config.num_heads * config.head_size], - ), - ], - ) - - model = helper.make_model(graph) - return model.SerializeToString() - - def create_group_query_attention_graph_prompt( config, past_kv_format=Formats.BSNH, @@ -575,204 +458,6 @@ def create_group_query_attention_graph_past( return model.SerializeToString() -def generate_random_padding_mask(max_seqlen, batch_size, device, mode="random"): - assert mode in ["full", "random", "third"] - if mode == "full": - lengths = torch.full((batch_size, 1), max_seqlen, device=device, dtype=torch.int32) - elif mode == "random": - lengths = torch.randint(max(1, max_seqlen - 20), max_seqlen, (batch_size, 1), device=device) - else: - lengths = torch.randint(max_seqlen // 3, max_seqlen, (batch_size, 1), device=device) - padding_mask = repeat(torch.arange(max_seqlen, device=device), "s -> b s", b=batch_size) < lengths - return padding_mask - - -def generate_qkv(q, k, v, query_padding_mask=None, key_padding_mask=None, kvpacked=False, qkvpacked=False): - """ - Arguments: - q: (batch_size, seqlen_q, nheads, d) - k: (batch_size, seqlen_k, nheads_k, d) - v: (batch_size, seqlen_k, nheads_k, d) - query_padding_mask: (batch_size, seqlen), bool - key_padding_mask: (batch_size, seqlen), bool - """ - assert not (kvpacked and qkvpacked) - batch_size, seqlen_q, nheads, d = q.shape - _, seqlen_k, nheads_k, _ = k.shape - assert k.shape == (batch_size, seqlen_k, nheads_k, d) - assert v.shape == (batch_size, seqlen_k, nheads_k, d) - - if query_padding_mask is not None: - q_unpad, indices_q, cu_seqlens_q, max_seqlen_q = unpad_input(q, query_padding_mask) - - def output_pad_fn(output_unpad): - return pad_input(output_unpad, indices_q, batch_size, seqlen_q) - - else: - q_unpad = rearrange(q, "b s h d -> (b s) h d") - cu_seqlens_q = torch.arange( - 0, (batch_size + 1) * seqlen_q, step=seqlen_q, dtype=torch.int32, device=q_unpad.device - ) - max_seqlen_q = seqlen_q - - def output_pad_fn(output_unpad): - return rearrange(output_unpad, "(b s) h d -> b s h d", b=batch_size) - - if key_padding_mask is not None: - k_unpad, indices_k, cu_seqlens_k, max_seqlen_k = unpad_input(k, key_padding_mask) - v_unpad, _, _, _ = unpad_input(v, key_padding_mask) - else: - k_unpad = rearrange(k, "b s h d -> (b s) h d") - v_unpad = rearrange(v, "b s h d -> (b s) h d") - cu_seqlens_k = torch.arange( - 0, (batch_size + 1) * seqlen_k, step=seqlen_k, dtype=torch.int32, device=k_unpad.device - ) - max_seqlen_k = seqlen_k - - if qkvpacked: - assert (query_padding_mask == key_padding_mask).all() - assert nheads == nheads_k - qkv_unpad = torch.stack([q_unpad, k_unpad, v_unpad], dim=1) - qkv = torch.stack([q, k, v], dim=2) - if query_padding_mask is not None: - - def dqkv_pad_fn(dqkv_unpad): - return pad_input(dqkv_unpad, indices_q, batch_size, seqlen_q) - - else: - - def dqkv_pad_fn(dqkv_unpad): - return rearrange(dqkv_unpad, "(b s) t h d -> b s t h d", b=batch_size) - - return ( - qkv_unpad.detach().requires_grad_(), - cu_seqlens_q, - max_seqlen_q, - qkv.detach().requires_grad_(), - output_pad_fn, - dqkv_pad_fn, - ) - elif kvpacked: - kv_unpad = torch.stack([k_unpad, v_unpad], dim=1) - kv = torch.stack([k, v], dim=2) - dq_pad_fn = output_pad_fn - if key_padding_mask is not None: - - def dkv_pad_fn(dkv_unpad): - return pad_input(dkv_unpad, indices_k, batch_size, seqlen_k) - - else: - - def dkv_pad_fn(dkv_unpad): - return rearrange(dkv_unpad, "(b s) t h d -> b s t h d", b=batch_size) - - return ( - q_unpad.detach().requires_grad_(), - kv_unpad.detach().requires_grad_(), - cu_seqlens_q, - cu_seqlens_k, - max_seqlen_q, - max_seqlen_k, - q.detach().requires_grad_(), - kv.detach().requires_grad_(), - output_pad_fn, - dq_pad_fn, - dkv_pad_fn, - ) - else: - dq_pad_fn = output_pad_fn - if key_padding_mask is not None: - - def dk_pad_fn(dk_unpad): - return pad_input(dk_unpad, indices_k, batch_size, seqlen_k) - - else: - - def dk_pad_fn(dk_unpad): - return rearrange(dk_unpad, "(b s) h d -> b s h d", b=batch_size) - - return ( - q_unpad.detach().requires_grad_(), - k_unpad.detach().requires_grad_(), - v_unpad.detach().requires_grad_(), - cu_seqlens_q, - cu_seqlens_k, - max_seqlen_q, - max_seqlen_k, - q.detach().requires_grad_(), - k.detach().requires_grad_(), - v.detach().requires_grad_(), - output_pad_fn, - dq_pad_fn, - dk_pad_fn, - ) - - -def create_inputs(config: Config, kv_packed=False, qkv_packed=True): - qkv = torch.randn( - config.batch_size, - config.sequence_length, - 3, - config.num_heads, - config.head_size, - device="cuda", - dtype=torch.float16, - requires_grad=False, - ) - key_padding_mask = generate_random_padding_mask( - config.sequence_length, config.batch_size, device="cuda", mode="random" - ) - qkv_unpad, cu_seqlens, max_seqlen, qkv, output_pad_fn, dqkv_pad_fn = generate_qkv( - *qkv.unbind(dim=2), key_padding_mask, key_padding_mask, kv_packed, qkv_packed - ) - return qkv_unpad, cu_seqlens, max_seqlen, qkv, output_pad_fn, dqkv_pad_fn, key_padding_mask - - -def generate_token_offset(cu_seqlens, max_seqlen): - token_offset = [] - token_padset = [] # These are the indices that contain padding tokens - for i in range(1, len(cu_seqlens)): - start = i - 1 - pre_seqlen = cu_seqlens[i - 1] - seqlen = cu_seqlens[i] - token_offset += range(start * max_seqlen, (start * max_seqlen) + (seqlen - pre_seqlen)) - token_padset += range((start * max_seqlen) + (seqlen - pre_seqlen), i * max_seqlen) - return numpy.asarray(token_offset + token_padset, dtype=numpy.int32) - - -def flash_attn_varlen_qkvpacked_func(qkv_unpad, cu_seqlens, token_offset, config, causal=False): - onnx_model_str = create_packed_multihead_attention_graph(config) - qkv_unpad = torch.swapdims(qkv_unpad, 1, 2) - ort_inputs = { - "query": qkv_unpad.detach().cpu().numpy(), - "token_offset": token_offset, - "cumulative_sequence_length": cu_seqlens.cpu().numpy(), - } - sess_options = SessionOptions() - ort_session = InferenceSession(onnx_model_str, sess_options, providers=[config.ep]) - ort_output = ort_session.run(None, ort_inputs) - output = torch.tensor(ort_output) - return output - - -def mha_func(q, k, v, config): - onnx_model_str = create_multihead_attention_graph(config) - q = torch.reshape(q, (config.batch_size, config.sequence_length, -1)) - k = torch.reshape(k, (config.batch_size, config.kv_sequence_length, -1)) - v = torch.reshape(v, (config.batch_size, config.kv_sequence_length, -1)) - ort_inputs = { - "query": q.detach().cpu().numpy(), - "key": k.detach().cpu().numpy(), - "value": v.detach().cpu().numpy(), - } - sess_options = SessionOptions() - ort_session = InferenceSession(onnx_model_str, sess_options, providers=[config.ep]) - ort_output = ort_session.run(None, ort_inputs) - ort_output = numpy.array(ort_output) - output = torch.tensor(ort_output) - return output - - def rotary_options_for_current_os(): # Reference implementation of rotary uses triton, which is not available in Windows. # So we only test rotary in Linux right now. @@ -1009,14 +694,6 @@ def gqa_past_func( return output, present_k, present_v -def construct_causal_mask(seqlen_q, seqlen_k, query_padding_mask=None, key_padding_mask=None, device=None): - row_idx = rearrange(torch.arange(seqlen_q, device=device, dtype=torch.long), "s -> s 1") - col_idx = torch.arange(seqlen_k, device=device, dtype=torch.long) - sk = seqlen_k if key_padding_mask is None else rearrange(key_padding_mask.sum(-1), "b -> b 1 1 1") - sq = seqlen_q if query_padding_mask is None else rearrange(query_padding_mask.sum(-1), "b -> b 1 1 1") - return col_idx > row_idx + sk - sq - - def construct_local_mask( seqlen_q, seqlen_k, @@ -1127,93 +804,6 @@ def attention_ref( return output.to(dtype=dtype_og), attention.to(dtype=dtype_og) -def attention_qkvpacked_ref( - qkv, - key_padding_mask=None, - dropout_p=0.0, - dropout_mask=None, - causal=False, - upcast=True, - reorder_ops=False, - use_smooth_softmax=False, -): - return attention_ref( - qkv[:, :, 0], - qkv[:, :, 1], - qkv[:, :, 2], - key_padding_mask, - key_padding_mask, - dropout_p, - dropout_mask, - upcast=upcast, - causal=causal, - reorder_ops=reorder_ops, - use_smooth_softmax=use_smooth_softmax, - ) - - -def parity_check_mha( - config, - packed, - rtol=1e-3, - atol=1e-3, -): - if packed: - qkv_unpad, cu_seqlens, _, qkv, output_pad_fn, _, key_padding_mask = create_inputs(config) - token_offset = generate_token_offset(cu_seqlens, config.sequence_length).reshape( - (config.batch_size, config.sequence_length) - ) - # ORT Flash - out_unpad = flash_attn_varlen_qkvpacked_func(qkv_unpad, cu_seqlens, token_offset, config, causal=False) - out_unpad = torch.squeeze(out_unpad, 0) - out = torch.reshape( - output_pad_fn(out_unpad), (config.batch_size, config.sequence_length, config.num_heads, config.head_size) - ) - out = out.detach().cpu().numpy() - # Pytorch to compare - out_ref, _ = attention_qkvpacked_ref(qkv, key_padding_mask, 0.0, None, causal=False) - out_ref = out_ref.detach().cpu().numpy() - else: - q = torch.randn( - config.batch_size, - config.sequence_length, - config.num_heads, - config.head_size, - device="cuda", - dtype=torch.float16, - requires_grad=False, - ) - k = torch.randn( - config.batch_size, - config.kv_sequence_length, - config.kv_num_heads, - config.head_size, - device="cuda", - dtype=torch.float16, - requires_grad=False, - ) - v = torch.randn( - config.batch_size, - config.kv_sequence_length, - config.kv_num_heads, - config.head_size, - device="cuda", - dtype=torch.float16, - requires_grad=False, - ) - out = mha_func(q, k, v, config) - out = torch.squeeze(out, 0) - out = torch.reshape(out, (config.batch_size, config.sequence_length, config.num_heads, config.head_size)) - out = out.detach().cpu().numpy() - # Pytorch to compare - out_ref, _ = attention_ref(q, k, v, None, None, 0.0, None, causal=False) - out_ref = out_ref.detach().cpu().numpy() - - numpy.testing.assert_allclose( - out, out_ref, rtol=rtol, atol=atol, equal_nan=True, err_msg=f" with {config} packed={packed}" - ) - - def rotary_embedding(*args, **kwargs): # Use local import since triton is not available in Windows. from rotary_flash import apply_rotary_emb @@ -1222,7 +812,7 @@ def rotary_embedding(*args, **kwargs): def parity_check_gqa_prompt( - config, + config: PromptConfig, causal=True, local=False, past_format=Formats.BNSH, @@ -1420,7 +1010,7 @@ def parity_check_gqa_prompt( def parity_check_gqa_prompt_no_buff( - config, + config: PromptConfig, causal=True, local=False, past_format=Formats.BNSH, @@ -1595,7 +1185,7 @@ def parity_check_gqa_prompt_no_buff( def parity_check_gqa_past( - config, + config: Config, causal=True, local=False, past_format=Formats.BNSH, @@ -1788,7 +1378,7 @@ def parity_check_gqa_past( def parity_check_gqa_past_no_buff( - config, + config: Config, causal=True, local=False, past_format=Formats.BNSH, @@ -2019,67 +1609,6 @@ def has_memory_efficient(): return True -def packed_mha_test_cases(): - batches = [2] if pipeline_mode else [1, 5] - seqs = [1024, 1025] if pipeline_mode else [1024, 1025, 2048] - num_h = [1, 3] if pipeline_mode else [1, 6, 16] - h_sizes = [16, 256] if pipeline_mode else [32, 40, 64, 80, 96, 128, 160, 192, 224, 256] - - for b in batches: - for s in seqs: - for n in num_h: - for h in h_sizes: - config = Config(b, s, s, 0, n, n, h) - yield str(config), config - - -def mha_test_cases(): - batches = [2] if pipeline_mode else [1, 5] - seqs = ( - [(1, 128), (113, 211), (2048, 2048)] - if pipeline_mode - else [ - (113, 203), - (128, 217), - (113, 211), - (108, 256), - (256, 512), - (512, 256), - (1024, 1024), - (1023, 1024), - (1024, 1023), - (2048, 2048), - ] - ) - num_h = [3] if pipeline_mode else [1, 6, 16] - h_sizes = [64] if pipeline_mode else [32, 40, 64, 80, 96, 128, 160, 192, 224, 256] - - for b in batches: - for s, s2 in seqs: - for n in num_h: - for h in h_sizes: - config = Config(b, s, s2, 0, n, n, h) - yield str(config), config - - -class TestMHA(unittest.TestCase): - @parameterized.expand(packed_mha_test_cases()) - def test_packed_mha(self, _, config): - if not has_flash_attention(): - return - os.environ["ORT_DISABLE_FLASH_ATTENTION"] = "0" - print("-------- TEST PACKED MHA ---------") - parity_check_mha(config, True) - - @parameterized.expand(mha_test_cases()) - def test_mha(self, _, config): - if not has_flash_attention(): - return - os.environ["ORT_DISABLE_FLASH_ATTENTION"] = "0" - print("-------- TEST MHA ---------") - parity_check_mha(config, False) - - def gqa_no_past_memory_efficient_test_cases(): batches = [3] if pipeline_mode else [1, 3, 5] seqs = ( @@ -2103,18 +1632,22 @@ def gqa_no_past_memory_efficient_test_cases(): for sq, skv in seqs: for n, n2 in num_h: for h in h_sizes: - for rotary, rotary_interleaved in rotary_options_for_current_os(): - for packed in [False, True]: - for softcap in [0.0, 50.0]: - config = PromptConfig(b, sq, skv, sq + skv + 8, n, n2, h) - yield ( - str(config) + f"{rotary}_{rotary_interleaved}_{packed}", - config, - rotary, - rotary_interleaved, - packed, - softcap, - ) + for local in [False, True]: + for rotary, rotary_interleaved in rotary_options_for_current_os(): + for packed in [False, True]: + for softcap in [0.0, 50.0]: + config = PromptConfig(b, sq, skv, sq + skv + 8, n, n2, h) + if rotary and h % 16 > 0: + continue + yield ( + str(config) + f"{local}_{rotary}_{rotary_interleaved}_{packed}", + config, + local, + rotary, + rotary_interleaved, + packed, + softcap, + ) def gqa_no_past_flash_attention_test_cases(): @@ -2144,9 +1677,12 @@ def gqa_no_past_flash_attention_test_cases(): for rotary, rotary_interleaved in rotary_options_for_current_os(): for packed in [False, True]: for softcap in [0.0, 50.0]: + if rotary and h % 16 > 0: + continue + config = PromptConfig(b, sq, skv, sq + skv + 8, n, n2, h) yield ( - str(config) + f"{local}_{rotary}_{rotary_interleaved}_{packed}", + str(config) + f"{local}_{rotary}_{rotary_interleaved}_{packed}_{softcap}", config, local, rotary, @@ -2183,19 +1719,22 @@ def gqa_past_memory_efficient_test_cases(): for s, s2 in seqs: for n, n2 in num_h: for h in h_sizes: - for rotary, rotary_interleaved in rotary_options_for_current_os(): - for packed in [False, True]: - for softcap in [0.0, 50.0]: - sp = random.randint(1, s2 - s) if s2 - s > 0 else 0 - config = Config(b, s, s2, sp, n, n2, h) - yield ( - str(config) + f"{rotary}_{rotary_interleaved}_{packed}", - config, - rotary, - rotary_interleaved, - packed, - softcap, - ) + for local in [False, True]: + for rotary, rotary_interleaved in rotary_options_for_current_os(): + for packed in [False, True]: + for softcap in [0.0, 50.0]: + if rotary and h % 16 > 0: + continue + config = Config(b, s, s2, n, n2, h) + yield ( + str(config) + f"{local}_{rotary}_{rotary_interleaved}_{packed}_{softcap}", + config, + local, + rotary, + rotary_interleaved, + packed, + softcap, + ) def gqa_past_flash_attention_test_cases(): @@ -2229,10 +1768,12 @@ def gqa_past_flash_attention_test_cases(): for rotary, rotary_interleaved in rotary_options_for_current_os(): for packed in [False, True]: for softcap in [0.0, 50.0]: - sp = random.randint(1, s2 - s) if s2 - s > 0 else 0 - config = Config(b, s, s2, sp, n, n2, h) + if rotary and h % 16 > 0: + continue + + config = Config(b, s, s2, n, n2, h) yield ( - str(config) + f"{local}_{rotary}_{rotary_interleaved}_{packed}", + str(config) + f"{local}_{rotary}_{rotary_interleaved}_{packed}_{softcap}", config, local, rotary, @@ -2272,7 +1813,10 @@ def gqa_interactive_one_batch_flash_attention_test_cases(): for local in [False, True]: for rotary, rotary_interleaved in rotary_options_for_current_os(): for packed in [False, True]: - config = Config(b, s, s2, -1, n, n2, h) + if rotary and h % 16 > 0: + continue + + config = Config(b, s, s2, n, n2, h) yield ( str(config) + f"{local}_{rotary}_{rotary_interleaved}_{packed}", config, @@ -2312,7 +1856,10 @@ def gqa_interactive_one_batch_memory_efficient_attention_test_cases(): for h in h_sizes: for rotary, rotary_interleaved in rotary_options_for_current_os(): for packed in [False, True]: - config = Config(b, s, s2, -1, n, n2, h) + if rotary and h % 16 > 0: + continue + + config = Config(b, s, s2, n, n2, h) yield ( str(config) + f"{rotary}_{rotary_interleaved}_{packed}", config, @@ -2410,12 +1957,13 @@ def test_gqa_interactive_one_batch_flash_attention(self, _, config, local, rotar @unittest.skipIf(not has_memory_efficient(), reason="Memory efficient FMHA is not available, skipping tests.") class TestMemoryEfficientGQA(unittest.TestCase): @parameterized.expand(gqa_no_past_memory_efficient_test_cases()) - def test_gqa_no_past_memory_efficient(self, _, config, rotary, rotary_interleaved, packed, softcap): + def test_gqa_no_past_memory_efficient(self, _, config, local, rotary, rotary_interleaved, packed, softcap): os.environ["ORT_DISABLE_FLASH_ATTENTION"] = "1" print("------- MEMORY EFFICIENT ATTENTION (PROMPT CASE) ---------") parity_check_gqa_prompt( config, + local=local, rtol=5e-3, atol=5e-3, past_format=Formats.BNSH, @@ -2427,6 +1975,7 @@ def test_gqa_no_past_memory_efficient(self, _, config, rotary, rotary_interleave ) parity_check_gqa_prompt_no_buff( config, + local=local, rtol=5e-3, atol=5e-3, past_format=Formats.BNSH, @@ -2438,12 +1987,13 @@ def test_gqa_no_past_memory_efficient(self, _, config, rotary, rotary_interleave ) @parameterized.expand(gqa_past_memory_efficient_test_cases()) - def test_gqa_past_memory_efficient(self, _, config, rotary, rotary_interleaved, packed, softcap): + def test_gqa_past_memory_efficient(self, _, config, local, rotary, rotary_interleaved, packed, softcap): os.environ["ORT_DISABLE_FLASH_ATTENTION"] = "1" print("-------- MEMORY EFFICIENT (TOKEN GEN) --------") parity_check_gqa_past( config, + local=local, past_format=Formats.BNSH, rtol=1e-3, atol=1e-3, @@ -2455,6 +2005,7 @@ def test_gqa_past_memory_efficient(self, _, config, rotary, rotary_interleaved, ) parity_check_gqa_past_no_buff( config, + local=local, past_format=Formats.BNSH, rtol=1e-3, atol=1e-3, diff --git a/onnxruntime/test/python/transformers/test_flash_attn_rocm.py b/onnxruntime/test/python/transformers/test_gqa_rocm.py similarity index 98% rename from onnxruntime/test/python/transformers/test_flash_attn_rocm.py rename to onnxruntime/test/python/transformers/test_gqa_rocm.py index a5910c28c2975..29ae1b6e44a78 100644 --- a/onnxruntime/test/python/transformers/test_flash_attn_rocm.py +++ b/onnxruntime/test/python/transformers/test_gqa_rocm.py @@ -3,7 +3,7 @@ import torch from parameterized import parameterized -from test_flash_attn_cuda import ( +from test_gqa_cuda import ( Formats, gqa_no_past_flash_attention_test_cases, gqa_past_flash_attention_test_cases, @@ -38,6 +38,7 @@ def test_gqa_no_past_flash_attention(self, _, config, local, rotary, rotary_inte rtol=0.001, atol=0.005, ) + parity_check_gqa_prompt_no_buff( config, local=local, diff --git a/onnxruntime/test/python/transformers/test_mha.py b/onnxruntime/test/python/transformers/test_mha.py index dc19e3ec95243..f6403636e79d9 100644 --- a/onnxruntime/test/python/transformers/test_mha.py +++ b/onnxruntime/test/python/transformers/test_mha.py @@ -41,15 +41,15 @@ def get_provider_support_info(provider: str, use_kv_cache: bool): device_id = torch.cuda.current_device() device = torch.device("cuda", device_id) - dtype = torch.float16 + dtypes = [torch.float16, torch.float] else: assert provider == "CPUExecutionProvider" formats = [InputFormats.Q_K_V_BSNH_BSNH_BSNH] if not use_kv_cache: formats.append(InputFormats.Q_K_V_BSNH_BNSH_BNSH) device = torch.device("cpu") - dtype = torch.float - return device, dtype, formats + dtypes = [torch.float] + return device, dtypes, formats def get_bias_support(format: InputFormats): @@ -211,10 +211,11 @@ def no_kv_cache_test_cases(provider: str, comprehensive: bool): return yield + # Lengths of arrays are prime numbers since modulo (% length) is used in non comprehensive mode. batch_sizes = [1, 2, 3] - sequence_lengths = [1, 16, 127, 128, 255, 256, 383, 384, 512] - heads = [1, 3, 4, 16] - head_sizes = [8, 16, 32, 40, 64, 80, 96, 128, 160, 192, 224, 256] + sequence_lengths = [1, 16, 127, 128, 256, 384, 512] + heads = [1, 2, 3, 4, 16] + head_sizes = [8, 16, 32, 40, 64, 80, 96, 128, 160, 192, 256] mask_formats = [ AttentionMaskFormat.Mask_None, @@ -223,7 +224,7 @@ def no_kv_cache_test_cases(provider: str, comprehensive: bool): ] atten_bias_options = get_atten_bias_support() - device, dtype, formats = get_provider_support_info(provider, False) + device, dtypes, formats = get_provider_support_info(provider, False) if comprehensive: sequence_lengths = [*sequence_lengths, 2048] # Large sequence length is slow and need a lot of memory for batch_size in batch_sizes: @@ -239,30 +240,31 @@ def no_kv_cache_test_cases(provider: str, comprehensive: bool): broadcast_attn_bias_dim_0, broadcast_attn_bias_dim_1, ) in atten_bias_options: - config = MultiHeadAttentionConfig( - batch_size=batch_size, - sequence_length=sequence_length, - num_heads=num_heads, - head_size=head_size, - causal=causal, - past_sequence_length=0, - kv_sequence_length=sequence_length, - max_cache_sequence_length=None, - provider=provider, - device=device, - dtype=dtype, - use_kv_cache=False, - share_past_present_buffer=False, - input_format=format, - has_bias=has_bias, - mask_format=mask_format, - has_attn_bias=has_attn_bias, - broadcast_attn_bias_dim_0=broadcast_attn_bias_dim_0, - broadcast_attn_bias_dim_1=broadcast_attn_bias_dim_1, - ) - yield config + for dtype in dtypes: + config = MultiHeadAttentionConfig( + batch_size=batch_size, + sequence_length=sequence_length, + num_heads=num_heads, + head_size=head_size, + causal=causal, + past_sequence_length=0, + kv_sequence_length=sequence_length, + max_cache_sequence_length=None, + provider=provider, + device=device, + dtype=dtype, + use_kv_cache=False, + share_past_present_buffer=False, + input_format=format, + has_bias=has_bias, + mask_format=mask_format, + has_attn_bias=has_attn_bias, + broadcast_attn_bias_dim_0=broadcast_attn_bias_dim_0, + broadcast_attn_bias_dim_1=broadcast_attn_bias_dim_1, + ) + yield config else: - test_cases = max(len(batch_sizes), len(sequence_lengths), len(heads), len(head_sizes)) + test_cases = 2 * max(len(batch_sizes), len(sequence_lengths), len(heads), len(head_sizes)) for i in range(test_cases): batch_size = batch_sizes[i % len(batch_sizes)] sequence_length = sequence_lengths[i % len(sequence_lengths)] @@ -272,6 +274,7 @@ def no_kv_cache_test_cases(provider: str, comprehensive: bool): has_attn_bias, broadcast_attn_bias_dim_0, broadcast_attn_bias_dim_1 = atten_bias_options[ i % len(atten_bias_options) ] + dtype = dtypes[i % len(dtypes)] for format in formats: for causal in get_causal_support(format): for has_bias in get_bias_support(format): @@ -304,11 +307,13 @@ def kv_cache_test_cases(provider: str, comprehensive: bool): return yield + # Lengths of arrays are prime numbers since modulo (% length) is used in non comprehensive mode. batch_sizes = [1, 2, 3] - sequence_lengths = [1, 15, 16, 255, 256, 512] - heads = [1, 3, 4, 16] - head_sizes = [8, 16, 32, 40, 64, 80, 96, 128, 160, 192, 224, 256] - device, dtype, formats = get_provider_support_info(provider, True) + sequence_lengths = [1, 15, 16, 255, 256, 384, 512] + heads = [1, 2, 3, 4, 16] + head_sizes = [8, 16, 32, 40, 64, 80, 96, 128, 160, 224, 256] + + device, dtypes, formats = get_provider_support_info(provider, True) mask_formats = [ AttentionMaskFormat.Mask_None, AttentionMaskFormat.Mask_1D_Key_SeqLen, @@ -328,38 +333,39 @@ def kv_cache_test_cases(provider: str, comprehensive: bool): for has_past_input in [True, False]: for mask_format in mask_formats: for has_bias in get_bias_support(format): - for ( - has_attn_bias, - broadcast_attn_bias_dim_0, - broadcast_attn_bias_dim_1, - ) in atten_bias_options: - sequence_length = 1 if has_past_input else past_sequence_length - past_seq_len = past_sequence_length if has_past_input else 0 - config = MultiHeadAttentionConfig( - batch_size=batch_size, - sequence_length=sequence_length, - num_heads=num_heads, - head_size=head_size, - causal=causal, - past_sequence_length=past_seq_len, - kv_sequence_length=sequence_length, - max_cache_sequence_length=None, - provider=provider, - device=device, - dtype=dtype, - use_kv_cache=True, - has_past_input=has_past_input, - share_past_present_buffer=False, - input_format=format, - has_bias=has_bias, - mask_format=mask_format, - has_attn_bias=has_attn_bias, - broadcast_attn_bias_dim_0=broadcast_attn_bias_dim_0, - broadcast_attn_bias_dim_1=broadcast_attn_bias_dim_1, - ) - yield config + for dtype in dtypes: + for ( + has_attn_bias, + broadcast_attn_bias_dim_0, + broadcast_attn_bias_dim_1, + ) in atten_bias_options: + sequence_length = 1 if has_past_input else past_sequence_length + past_seq_len = past_sequence_length if has_past_input else 0 + config = MultiHeadAttentionConfig( + batch_size=batch_size, + sequence_length=sequence_length, + num_heads=num_heads, + head_size=head_size, + causal=causal, + past_sequence_length=past_seq_len, + kv_sequence_length=sequence_length, + max_cache_sequence_length=None, + provider=provider, + device=device, + dtype=dtype, + use_kv_cache=True, + has_past_input=has_past_input, + share_past_present_buffer=False, + input_format=format, + has_bias=has_bias, + mask_format=mask_format, + has_attn_bias=has_attn_bias, + broadcast_attn_bias_dim_0=broadcast_attn_bias_dim_0, + broadcast_attn_bias_dim_1=broadcast_attn_bias_dim_1, + ) + yield config else: - test_cases = max(len(batch_sizes), len(sequence_lengths), len(heads), len(head_sizes)) + test_cases = 2 * max(len(batch_sizes), len(sequence_lengths), len(heads), len(head_sizes)) for i in range(test_cases): batch_size = batch_sizes[i % len(batch_sizes)] past_sequence_length = sequence_lengths[i % len(sequence_lengths)] @@ -369,6 +375,8 @@ def kv_cache_test_cases(provider: str, comprehensive: bool): has_attn_bias, broadcast_attn_bias_dim_0, broadcast_attn_bias_dim_1 = atten_bias_options[ i % len(atten_bias_options) ] + dtype = dtypes[i % len(dtypes)] + for format in formats: for causal in get_causal_support(format): for has_past_input in [True, False]: @@ -401,7 +409,7 @@ def kv_cache_test_cases(provider: str, comprehensive: bool): def lean_attention_test_cases(provider: str, comprehensive: bool): - if provider == "CUDAExecutionProvider" and get_compute_capability() < 80: + if provider != "CUDAExecutionProvider" or get_compute_capability() < 80: return yield @@ -409,7 +417,7 @@ def lean_attention_test_cases(provider: str, comprehensive: bool): sequence_lengths = [2, 15, 16, 255, 256, 512, 1024, 2048, 4096, 8192] if comprehensive else [2, 255, 512] heads = [1, 4, 16] if comprehensive else [1, 4] head_sizes = [64, 128] - device, dtype, formats = get_provider_support_info(provider, True) + device, dtypes, formats = get_provider_support_info(provider, True) mask_formats = [AttentionMaskFormat.Mask_None] sequence_lengths = [*sequence_lengths, 2048] # Large sequence length is slow and need a lot of memory @@ -433,7 +441,7 @@ def lean_attention_test_cases(provider: str, comprehensive: bool): max_cache_sequence_length=None, provider=provider, device=device, - dtype=dtype, + dtype=dtypes[0], use_kv_cache=True, has_past_input=True, share_past_present_buffer=False, @@ -453,7 +461,7 @@ def no_kv_cache_multi_thread_test_cases(provider: str, comprehensive: bool): heads = [4] head_sizes = [8, 16, 32, 40, 64, 80, 96, 128, 160, 192, 224, 256] if comprehensive else [32, 64] - device, dtype, formats = get_provider_support_info(provider, False) + device, dtypes, formats = get_provider_support_info(provider, False) for format in formats: for causal in get_causal_support(format): @@ -473,7 +481,7 @@ def no_kv_cache_multi_thread_test_cases(provider: str, comprehensive: bool): max_cache_sequence_length=None, provider=provider, device=device, - dtype=dtype, + dtype=dtypes[0], use_kv_cache=False, share_past_present_buffer=False, input_format=format, @@ -493,7 +501,7 @@ def kv_cache_multi_thread_test_cases(provider: str, comprehensive: bool): head_sizes = [8, 16, 32, 40, 64, 80, 96, 128, 160, 192, 224, 256] if comprehensive else [32, 64] sequence_length = 1 - device, dtype, formats = get_provider_support_info(provider, True) + device, dtypes, formats = get_provider_support_info(provider, True) for format in formats: for causal in get_causal_support(format): @@ -513,7 +521,7 @@ def kv_cache_multi_thread_test_cases(provider: str, comprehensive: bool): max_cache_sequence_length=None, provider=provider, device=device, - dtype=dtype, + dtype=dtypes[0], use_kv_cache=True, has_past_input=True, share_past_present_buffer=False, diff --git a/onnxruntime/test/python/transformers/test_mha_flash_attn.py b/onnxruntime/test/python/transformers/test_mha_flash_attn.py new file mode 100644 index 0000000000000..f87370e37d21a --- /dev/null +++ b/onnxruntime/test/python/transformers/test_mha_flash_attn.py @@ -0,0 +1,452 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# ------------------------------------------------------------------------- +import os +import unittest + +import numpy +import torch +from bert_padding import pad_input, unpad_input +from einops import rearrange, repeat +from onnx import TensorProto, helper +from parameterized import parameterized +from test_gqa_cuda import attention_ref, has_flash_attention + +from onnxruntime import InferenceSession, SessionOptions + +torch.manual_seed(0) + +pipeline_mode = True # Reduces number of tests so pipeline doesn't time out + + +class Formats: + BSNH = 0 + BNSH = 1 + + +class Config: + batch_size = 0 + sequence_length = 0 + kv_sequence_length = 0 # this is past sequence length when there is past state. + num_heads = 0 + kv_num_heads = 0 + head_size = 0 + ep = "CUDAExecutionProvider" + + def __init__(self, batch_size, sequence_length, kv_sequence_length, num_heads, kv_num_heads, head_size): + self.batch_size = batch_size + self.sequence_length = sequence_length + self.kv_sequence_length = kv_sequence_length + self.num_heads = num_heads + self.kv_num_heads = kv_num_heads + self.head_size = head_size + + def __repr__(self): + short_ep = self.ep[: -len("ExecutionProvider")].lower() + return ( + f"Config(batch_size={self.batch_size}, sequence_length={self.sequence_length}, " + f"kv_sequence_length={self.kv_sequence_length}, " + f"num_heads={self.num_heads}, kv_num_heads={self.kv_num_heads}, head_size={self.head_size}, ep={short_ep})" + ) + + +def create_packed_multihead_attention_graph(config: Config): + nodes = [ + helper.make_node( + "PackedMultiHeadAttention", + [ + "query", + "", + "", + "", + "token_offset", + "cumulative_sequence_length", + ], + ["output"], + "PackedMultiHeadAttention_0", + num_heads=config.num_heads, + domain="com.microsoft", + ), + ] + + graph = helper.make_graph( + nodes, + "PackedMultiHeadAttention_Graph", + [ + helper.make_tensor_value_info( + "query", + TensorProto.FLOAT16, + [ + -1, + config.num_heads, + 3, + config.head_size, + ], + ), + helper.make_tensor_value_info( + "token_offset", TensorProto.INT32, [config.batch_size, config.sequence_length] + ), + helper.make_tensor_value_info("cumulative_sequence_length", TensorProto.INT32, [config.batch_size + 1]), + ], + [ + helper.make_tensor_value_info( + "output", + TensorProto.FLOAT16, + [-1, config.num_heads * config.head_size], + ), + ], + ) + + model = helper.make_model(graph) + return model.SerializeToString() + + +def create_multihead_attention_graph(config: Config): + nodes = [ + helper.make_node( + "MultiHeadAttention", + [ + "query", + "key", + "value", + ], + ["output"], + "MultiHeadAttention_0", + num_heads=config.num_heads, + domain="com.microsoft", + ), + ] + + graph = helper.make_graph( + nodes, + "MultiHeadAttention_Graph", + [ + helper.make_tensor_value_info( + "query", + TensorProto.FLOAT16, + [ + config.batch_size, + config.sequence_length, + config.num_heads * config.head_size, + ], + ), + helper.make_tensor_value_info( + "key", + TensorProto.FLOAT16, + [ + config.batch_size, + config.kv_sequence_length, + config.num_heads * config.head_size, + ], + ), + helper.make_tensor_value_info( + "value", + TensorProto.FLOAT16, + [ + config.batch_size, + config.kv_sequence_length, + config.num_heads * config.head_size, + ], + ), + ], + [ + helper.make_tensor_value_info( + "output", + TensorProto.FLOAT16, + [config.batch_size, config.sequence_length, config.num_heads * config.head_size], + ), + ], + ) + + model = helper.make_model(graph) + return model.SerializeToString() + + +def generate_random_padding_mask(max_seqlen, batch_size, device, mode="random"): + assert mode in ["full", "random", "third"] + if mode == "full": + lengths = torch.full((batch_size, 1), max_seqlen, device=device, dtype=torch.int32) + elif mode == "random": + lengths = torch.randint(max(1, max_seqlen - 20), max_seqlen, (batch_size, 1), device=device) + else: + lengths = torch.randint(max_seqlen // 3, max_seqlen, (batch_size, 1), device=device) + padding_mask = repeat(torch.arange(max_seqlen, device=device), "s -> b s", b=batch_size) < lengths + return padding_mask + + +def generate_packed_qkv(q, k, v, query_padding_mask=None, key_padding_mask=None): + """ + Arguments: + q: (batch_size, seqlen_q, nheads, d) + k: (batch_size, seqlen_k, nheads_k, d) + v: (batch_size, seqlen_k, nheads_k, d) + query_padding_mask: (batch_size, seqlen), bool + key_padding_mask: (batch_size, seqlen), bool + """ + batch_size, seqlen_q, nheads, d = q.shape + _, seqlen_k, nheads_k, _ = k.shape + assert k.shape == (batch_size, seqlen_k, nheads_k, d) + assert v.shape == (batch_size, seqlen_k, nheads_k, d) + + if query_padding_mask is not None: + q_unpad, indices_q, cu_seqlens_q, max_seqlen_q = unpad_input(q, query_padding_mask) + + def output_pad_fn(output_unpad): + return pad_input(output_unpad, indices_q, batch_size, seqlen_q) + + else: + q_unpad = rearrange(q, "b s h d -> (b s) h d") + cu_seqlens_q = torch.arange( + 0, (batch_size + 1) * seqlen_q, step=seqlen_q, dtype=torch.int32, device=q_unpad.device + ) + max_seqlen_q = seqlen_q + + def output_pad_fn(output_unpad): + return rearrange(output_unpad, "(b s) h d -> b s h d", b=batch_size) + + if key_padding_mask is not None: + k_unpad, _, _, _ = unpad_input(k, key_padding_mask) + v_unpad, _, _, _ = unpad_input(v, key_padding_mask) + else: + k_unpad = rearrange(k, "b s h d -> (b s) h d") + v_unpad = rearrange(v, "b s h d -> (b s) h d") + + assert (query_padding_mask == key_padding_mask).all() + assert nheads == nheads_k + qkv_unpad = torch.stack([q_unpad, k_unpad, v_unpad], dim=1) + qkv = torch.stack([q, k, v], dim=2) + if query_padding_mask is not None: + + def dqkv_pad_fn(dqkv_unpad): + return pad_input(dqkv_unpad, indices_q, batch_size, seqlen_q) + + else: + + def dqkv_pad_fn(dqkv_unpad): + return rearrange(dqkv_unpad, "(b s) t h d -> b s t h d", b=batch_size) + + return ( + qkv_unpad.detach().requires_grad_(), + cu_seqlens_q, + max_seqlen_q, + qkv.detach().requires_grad_(), + output_pad_fn, + dqkv_pad_fn, + ) + + +def create_inputs(config: Config): + qkv = torch.randn( + config.batch_size, + config.sequence_length, + 3, + config.num_heads, + config.head_size, + device="cuda", + dtype=torch.float16, + requires_grad=False, + ) + padding_mask = generate_random_padding_mask(config.sequence_length, config.batch_size, device="cuda", mode="random") + qkv_unpad, cu_seqlens, max_seqlen, qkv, output_pad_fn, dqkv_pad_fn = generate_packed_qkv( + *qkv.unbind(dim=2), padding_mask, padding_mask + ) + return qkv_unpad, cu_seqlens, max_seqlen, qkv, output_pad_fn, dqkv_pad_fn, padding_mask + + +def generate_token_offset(cu_seqlens, max_seqlen): + token_offset = [] + token_padset = [] # These are the indices that contain padding tokens + for i in range(1, len(cu_seqlens)): + start = i - 1 + pre_seqlen = cu_seqlens[i - 1] + seqlen = cu_seqlens[i] + token_offset += range(start * max_seqlen, (start * max_seqlen) + (seqlen - pre_seqlen)) + token_padset += range((start * max_seqlen) + (seqlen - pre_seqlen), i * max_seqlen) + return numpy.asarray(token_offset + token_padset, dtype=numpy.int32) + + +def flash_attn_varlen_qkvpacked_func(qkv_unpad, cu_seqlens, token_offset, config): + onnx_model_str = create_packed_multihead_attention_graph(config) + qkv_unpad = torch.swapdims(qkv_unpad, 1, 2) + ort_inputs = { + "query": qkv_unpad.detach().cpu().numpy(), + "token_offset": token_offset, + "cumulative_sequence_length": cu_seqlens.cpu().numpy(), + } + sess_options = SessionOptions() + ort_session = InferenceSession(onnx_model_str, sess_options, providers=[config.ep]) + ort_output = ort_session.run(None, ort_inputs) + output = torch.tensor(ort_output) + return output + + +def mha_func(q, k, v, config): + onnx_model_str = create_multihead_attention_graph(config) + q = torch.reshape(q, (config.batch_size, config.sequence_length, -1)) + k = torch.reshape(k, (config.batch_size, config.kv_sequence_length, -1)) + v = torch.reshape(v, (config.batch_size, config.kv_sequence_length, -1)) + ort_inputs = { + "query": q.detach().cpu().numpy(), + "key": k.detach().cpu().numpy(), + "value": v.detach().cpu().numpy(), + } + sess_options = SessionOptions() + ort_session = InferenceSession(onnx_model_str, sess_options, providers=[config.ep]) + ort_output = ort_session.run(None, ort_inputs) + ort_output = numpy.array(ort_output) + output = torch.tensor(ort_output) + return output + + +def attention_qkvpacked_ref( + qkv, + key_padding_mask=None, + dropout_p=0.0, + dropout_mask=None, + causal=False, + upcast=True, + reorder_ops=False, + use_smooth_softmax=False, +): + return attention_ref( + qkv[:, :, 0], + qkv[:, :, 1], + qkv[:, :, 2], + key_padding_mask, + key_padding_mask, + dropout_p, + dropout_mask, + upcast=upcast, + causal=causal, + reorder_ops=reorder_ops, + use_smooth_softmax=use_smooth_softmax, + ) + + +def parity_check_mha( + config, + packed, + rtol=1e-3, + atol=1e-3, +): + if packed: + qkv_unpad, cu_seqlens, _, qkv, output_pad_fn, _, key_padding_mask = create_inputs(config) + token_offset = generate_token_offset(cu_seqlens, config.sequence_length).reshape( + (config.batch_size, config.sequence_length) + ) + # ORT Flash + out_unpad = flash_attn_varlen_qkvpacked_func(qkv_unpad, cu_seqlens, token_offset, config) + out_unpad = torch.squeeze(out_unpad, 0) + out = torch.reshape( + output_pad_fn(out_unpad), (config.batch_size, config.sequence_length, config.num_heads, config.head_size) + ) + out = out.detach().cpu().numpy() + # Pytorch to compare + out_ref, _ = attention_qkvpacked_ref(qkv, key_padding_mask, 0.0, None, causal=False) + out_ref = out_ref.detach().cpu().numpy() + else: + q = torch.randn( + config.batch_size, + config.sequence_length, + config.num_heads, + config.head_size, + device="cuda", + dtype=torch.float16, + requires_grad=False, + ) + k = torch.randn( + config.batch_size, + config.kv_sequence_length, + config.kv_num_heads, + config.head_size, + device="cuda", + dtype=torch.float16, + requires_grad=False, + ) + v = torch.randn( + config.batch_size, + config.kv_sequence_length, + config.kv_num_heads, + config.head_size, + device="cuda", + dtype=torch.float16, + requires_grad=False, + ) + out = mha_func(q, k, v, config) + out = torch.squeeze(out, 0) + out = torch.reshape(out, (config.batch_size, config.sequence_length, config.num_heads, config.head_size)) + out = out.detach().cpu().numpy() + # Pytorch to compare + out_ref, _ = attention_ref(q, k, v, None, None, 0.0, None, causal=False) + out_ref = out_ref.detach().cpu().numpy() + + numpy.testing.assert_allclose( + out, out_ref, rtol=rtol, atol=atol, equal_nan=True, err_msg=f" with {config} packed={packed}" + ) + + +def packed_mha_test_cases(): + batch_sizes = [2] if pipeline_mode else [1, 5] + sequence_lengths = [1024, 1025] if pipeline_mode else [1024, 1025, 2048] + num_heads = [1, 3] if pipeline_mode else [1, 6, 16] + head_sizes = [16, 256] if pipeline_mode else [32, 40, 64, 80, 96, 128, 160, 192, 224, 256] + + for b in batch_sizes: + for s in sequence_lengths: + for n in num_heads: + for h in head_sizes: + config = Config(b, s, s, n, n, h) + yield str(config), config + + +def mha_test_cases(): + batch_sizes = [2] if pipeline_mode else [1, 5] + sequence_lengths = ( + [(1, 128), (113, 211), (2048, 2048)] + if pipeline_mode + else [ + (113, 203), + (128, 217), + (113, 211), + (108, 256), + (256, 512), + (512, 256), + (1024, 1024), + (1023, 1024), + (1024, 1023), + (2048, 2048), + ] + ) + num_heads = [3] if pipeline_mode else [1, 6, 16] + head_sizes = [64] if pipeline_mode else [32, 40, 64, 80, 96, 128, 160, 192, 224, 256] + + for b in batch_sizes: + for s, kv_sequence_length in sequence_lengths: + for n in num_heads: + for h in head_sizes: + config = Config(b, s, kv_sequence_length, n, n, h) + yield str(config), config + + +class TestMHA(unittest.TestCase): + @parameterized.expand(packed_mha_test_cases()) + def test_packed_mha(self, _, config): + if not has_flash_attention(): + return + os.environ["ORT_DISABLE_FLASH_ATTENTION"] = "0" + print("-------- TEST PACKED MHA ---------") + parity_check_mha(config, True) + + @parameterized.expand(mha_test_cases()) + def test_mha(self, _, config): + if not has_flash_attention(): + return + os.environ["ORT_DISABLE_FLASH_ATTENTION"] = "0" + print("-------- TEST MHA ---------") + parity_check_mha(config, False) + + +if __name__ == "__main__": + unittest.main() diff --git a/onnxruntime/test/python/transformers/test_parity_t5_mha.py b/onnxruntime/test/python/transformers/test_parity_t5_mha.py index 7eae2f0a231d4..b90fb410b9b32 100644 --- a/onnxruntime/test/python/transformers/test_parity_t5_mha.py +++ b/onnxruntime/test/python/transformers/test_parity_t5_mha.py @@ -848,27 +848,28 @@ def test_t5_cross_attention_decoder_masked_mha_cpu(self): def test_t5_self_attention_decoder_masked_mha_cpu(self): return self.test_t5_self_attention_decoder_masked_mha(use_cuda=False) - def test_t5_self_attention_decoder_masked_mha_with_beams(self): - """ - Test DecoderMaskedMultiHeadAttention self-attention case with beam_width > 1. - Compare the results on CUDA and CPU EPs. - """ - batch_size = 4 - seq_len = 1 - num_heads = 2 - head_size = 32 - kv_sequence_length = 2 - beam_width = 2 - compare_t5_self_attention_decoder( - batch_size, - seq_len, - num_heads, - head_size, - kv_sequence_length, - use_dmmha=True, - use_cuda=False, - beam_width=beam_width, - ) + # TODO: uncomment this test once DMMHA CPU kernel parity mismatch is fixed + # def test_t5_self_attention_decoder_masked_mha_with_beams(self): + # """ + # Test DecoderMaskedMultiHeadAttention self-attention case with beam_width > 1. + # Compare the results on CUDA and CPU EPs. + # """ + # batch_size = 4 + # seq_len = 1 + # num_heads = 2 + # head_size = 32 + # kv_sequence_length = 2 + # beam_width = 2 + # compare_t5_self_attention_decoder( + # batch_size, + # seq_len, + # num_heads, + # head_size, + # kv_sequence_length, + # use_dmmha=True, + # use_cuda=False, + # beam_width=beam_width, + # ) if __name__ == "__main__": diff --git a/onnxruntime/test/python/transformers/whisper_model_generator.py b/onnxruntime/test/python/transformers/whisper_model_generator.py index 37f877dbe5685..5527df489b846 100644 --- a/onnxruntime/test/python/transformers/whisper_model_generator.py +++ b/onnxruntime/test/python/transformers/whisper_model_generator.py @@ -391,9 +391,14 @@ def create_whisper_decoder_attention( # before attention is fused inputs = [ helper.make_tensor_value_info("input_0", TensorProto.FLOAT, ["batch_size", 1500, hidden_size]), - helper.make_tensor_value_info("dummy_input_int64", TensorProto.INT64, ["dummy_input_1d_int64"]), - helper.make_tensor_value_info("dummy_input_fp32", TensorProto.FLOAT, ["dummy_input_1d_fp32"]), ] + if not fused: + inputs.extend( + [ + helper.make_tensor_value_info("dummy_input_int64", TensorProto.INT64, ["dummy_input_1d_int64"]), + helper.make_tensor_value_info("dummy_input_fp32", TensorProto.FLOAT, ["dummy_input_1d_fp32"]), + ] + ) outputs = [ helper.make_tensor_value_info( "present.0.decoder.key", TensorProto.FLOAT, ["batch_size", num_heads, 1500, head_size] @@ -444,13 +449,12 @@ def create_whisper_decoder_attention( "Attention_0_qkv_weight", "Attention_0_qkv_bias", "", - "", - "attention_add_qk", ], ["attn_output", "present_0_decoder"], "Attention_0", domain="com.microsoft", num_heads=num_heads, + unidirectional=1, ), helper.make_node( "Gather", @@ -717,38 +721,39 @@ def create_whisper_decoder_attention( ) # Create nodes that make attention mask - nodes.extend( - [ - # "attention_mask" is (decoder_seq_len, decoder_seq_len) but is assumed to be (1, 1) for this test. - # There are other nodes that automatically set the attention mask size correctly but those nodes do not - # impact the attention fusion. Hence, this assumption is made in order to simplify the inputs for the - # following nodes. - helper.make_node( - "Where", - ["all_ones", "where_filter_constant", "dummy_input_fp32"], - ["where_output"], - "mask_filter_where", - ), - helper.make_node( - "Unsqueeze", - ["where_output", "dummy_input_int64"], - ["unsqueeze_mask_output_1"], - "unsqueeze_attn_mask_1", - ), - helper.make_node( - "Unsqueeze", - ["unsqueeze_mask_output_1", "dummy_input_int64"], - ["unsqueeze_mask_output_2"], - "unsqueeze_attn_mask_2", - ), - helper.make_node( - "Expand", - inputs=["unsqueeze_mask_output_2", "dummy_input_int64"], - outputs=["attention_add_qk"], - name="expand_mask_from_(b,1,m,m)_to_(b,n,m,m)", - ), - ] - ) + if not fused: + nodes.extend( + [ + # "attention_mask" is (decoder_seq_len, decoder_seq_len) but is assumed to be (1, 1) for this test. + # There are other nodes that automatically set the attention mask size correctly but those nodes do not + # impact the attention fusion. Hence, this assumption is made in order to simplify the inputs for the + # following nodes. + helper.make_node( + "Where", + ["all_ones", "where_filter_constant", "dummy_input_fp32"], + ["where_output"], + "mask_filter_where", + ), + helper.make_node( + "Unsqueeze", + ["where_output", "dummy_input_int64"], + ["unsqueeze_mask_output_1"], + "unsqueeze_attn_mask_1", + ), + helper.make_node( + "Unsqueeze", + ["unsqueeze_mask_output_1", "dummy_input_int64"], + ["unsqueeze_mask_output_2"], + "unsqueeze_attn_mask_2", + ), + helper.make_node( + "Expand", + inputs=["unsqueeze_mask_output_2", "dummy_input_int64"], + outputs=["attention_add_qk"], + name="expand_mask_from_(b,1,m,m)_to_(b,n,m,m)", + ), + ] + ) # Create final nodes to conclude attention nodes.append( @@ -825,13 +830,6 @@ def create_whisper_decoder_attention( float_tensor("matmul_after_attn_initializer", [hidden_size, hidden_size]), float_tensor("add_after_attn_initializer", [hidden_size]), ] - # Add initializers for attention mask - initializers.extend( - [ - numpy_helper.from_array(np.array([[1]], dtype=bool), name="all_ones"), - numpy_helper.from_array(np.array([1], dtype="float32"), name="where_filter_constant"), - ] - ) if fused: initializers.extend( @@ -845,6 +843,8 @@ def create_whisper_decoder_attention( else: initializers.extend( [ + numpy_helper.from_array(np.array([[1]], dtype=bool), name="all_ones"), + numpy_helper.from_array(np.array([1], dtype="float32"), name="where_filter_constant"), numpy_helper.from_array(np.array(num_heads, dtype="int64"), name="num_heads_int"), numpy_helper.from_array(np.array([num_heads], dtype="int64"), name="num_heads"), numpy_helper.from_array(np.array([head_size], dtype="int64"), name="head_size"), @@ -1327,6 +1327,7 @@ def create_whisper_decoder_with_past_multihead_self_attention( "Attention_0", domain="com.microsoft", num_heads=num_heads, + unidirectional=1, ), ] ) diff --git a/onnxruntime/test/qnn_ctx_gen/README.md b/onnxruntime/test/qnn_ctx_gen/README.md deleted file mode 100644 index 97ab89d79cbd2..0000000000000 --- a/onnxruntime/test/qnn_ctx_gen/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# ONNXRuntime Qnn Context Generator - -This tool provides the way to generate Onnx models that wraps QNN context binary warpt with weight sharing enabled. The options to use with the tool are listed below: - -`onnxruntime_qnn_ctx_gen [options...] model_path,model_path` - -./onnxruntime_qnn_ctx_gen -v -i "soc_model|60 htp_graph_finalization_optimization_mode|3" -C "ep.context_enable|1 ep.context_embed_mode|0" /mnt/c/model1.onnx,/mnt/c/model2.onnx - -Options: - - -v: Show verbose information. - - -C: [session_config_entries]: Specify session configuration entries as key-value pairs: -C "| |" - Refer to onnxruntime_session_options_config_keys.h for valid keys and values. - [Example] -C "ep.context_enable|1 ep.context_embed_mode|0" - - -i: [provider_options]: Specify QNN EP specific runtime options as key value pairs. Different runtime options available are: - [Usage]: -i '| |' - - [backend_path]: QNN backend path. e.g '/folderpath/libQnnHtp.so', '/winfolderpath/QnnHtp.dll'. Default to HTP backend lib in current folder. - [vtcm_mb]: QNN VTCM size in MB. default to 0(not set). - [htp_graph_finalization_optimization_mode]: QNN graph finalization optimization mode, options: '0', '1', '2', '3', default is '0'. - [soc_model]: The SoC Model number. Refer to QNN SDK documentation for specific values. Defaults to '0' (unknown). - [htp_arch]: The minimum HTP architecture. The driver will use ops compatible with this architecture. eg: '0', '68', '69', '73', '75'. Defaults to '0' (none). - [enable_htp_fp16_precision]: Enable the HTP_FP16 precision so that the float32 model will be inferenced with fp16 precision. - Otherwise, it will be fp32 precision. Only works for float32 model. Defaults to '0' (with FP32 precision.). - [enable_htp_weight_sharing]: Allows common weights across graphs to be shared and stored in a single context binary. Defaults to '1' (enabled). - [Example] -i "vtcm_mb|8 htp_arch|73" - - -h: help. - diff --git a/onnxruntime/test/qnn_ctx_gen/main.cc b/onnxruntime/test/qnn_ctx_gen/main.cc deleted file mode 100644 index bb5007b40b072..0000000000000 --- a/onnxruntime/test/qnn_ctx_gen/main.cc +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// onnxruntime dependencies -#include "test_configuration.h" -#include -#include -#include -#include "command_args_parser.h" -#include - -#include "core/session/onnxruntime_session_options_config_keys.h" -#include "core/session/inference_session.h" -#include "core/session/ort_env.h" -#include "core/providers/provider_factory_creators.h" -#include "core/common/logging/sinks/clog_sink.h" - -#include "core/graph/model.h" -#include "core/session/environment.h" -#include "core/common/logging/logging.h" - -using namespace onnxruntime; -const OrtApi* g_ort = NULL; -std::unique_ptr ort_env; - -static void CheckStatus(const Status& status) { - if (status.Code() != common::StatusCode::OK) { - std::string msg = status.ErrorMessage(); - throw Ort::Exception(std::move(msg), OrtErrorCode::ORT_FAIL); - } -} - -static int64_t GetNodeAttr(const Node& node, const std::string& attr_name, int64_t default_val) { - const auto& attributes = node.GetAttributes(); - if (auto entry = attributes.find(attr_name); entry != attributes.end()) { - return entry->second.i(); - } - - return default_val; -} - -static const std::string& GetNodeAttr(const Node& node, const std::string& attr_name, const std::string& default_val) { - const auto& attributes = node.GetAttributes(); - if (auto entry = attributes.find(attr_name); entry != attributes.end()) { - return entry->second.s(); - } - - return default_val; -} - -// from the last context cache Onnx model, find the EPContext node with main_context=1, -// and get the QNN context binary file name, this context binary contains all graphs from all Onnx models -// get the max spill fill buffer size -static void GetLastContextBinaryFileName(const std::basic_string last_onnx_ctx_file, - std::string& last_ctx_bin_file, - int64_t& max_size) { - max_size = 0; - std::shared_ptr ctx_model; - CheckStatus(Model::Load(ToPathString(last_onnx_ctx_file), ctx_model, nullptr, - (*((OrtEnv*)*ort_env.get())->GetEnvironment().GetLoggingManager()).DefaultLogger())); - auto& ctx_graph = ctx_model->MainGraph(); - for (auto& node : ctx_graph.Nodes()) { - if (node.OpType() == "EPContext") { - int64_t is_main_context = GetNodeAttr(node, "main_context", static_cast(0)); - max_size = GetNodeAttr(node, "max_size", static_cast(0)); - if (1 == is_main_context) { - last_ctx_bin_file = GetNodeAttr(node, "ep_cache_context", ""); - return; - } - } - } -} - -// Update generated context cache Onnx model to make the main EPContext node point to -// the last QNN context binary file -// Remove not used QNN context binary file, only keep the last one which contains all graphs -static void UpdateEpContextModel(const std::vector>& ep_ctx_files, - const std::string& last_qnn_ctx_binary_file_name, - int64_t max_size) { - for (auto ep_ctx_file : ep_ctx_files) { - std::shared_ptr ctx_model; - auto path_str = ToPathString(ep_ctx_file); - CheckStatus(Model::Load(path_str, ctx_model, nullptr, - (*((OrtEnv*)*ort_env.get())->GetEnvironment().GetLoggingManager()).DefaultLogger())); - auto& ctx_graph = ctx_model->MainGraph(); - GraphViewer graph_viewer(ctx_graph); - auto path = std::filesystem::path(path_str); - - for (auto& node : ctx_graph.Nodes()) { - if (node.OpType() == "EPContext") { - int64_t is_main_context = GetNodeAttr(node, "main_context", static_cast(0)); - if (1 == is_main_context) { - std::string old_qnn_ctx_binary_file_name = GetNodeAttr(node, "ep_cache_context", ""); - auto file_path = path.replace_filename(old_qnn_ctx_binary_file_name); - std::remove(file_path.string().c_str()); - node.ClearAttribute("ep_cache_context"); - node.AddAttribute("ep_cache_context", last_qnn_ctx_binary_file_name); - node.ClearAttribute("max_size"); - node.AddAttribute("max_size", max_size); - } - } - } - std::remove(ToUTF8String(ep_ctx_file).c_str()); - CheckStatus(Model::Save(*ctx_model.get(), ToPathString(ep_ctx_file))); - } -} - -#ifdef _WIN32 -int real_main(int argc, wchar_t* argv[]) { -#else -int real_main(int argc, char* argv[]) { -#endif - g_ort = OrtGetApiBase()->GetApi(ORT_API_VERSION); - qnnctxgen::TestConfig test_config; - if (!qnnctxgen::CommandLineParser::ParseArguments(test_config, argc, argv)) { - qnnctxgen::CommandLineParser::ShowUsage(); - return -1; - } - - { - bool failed = false; - ORT_TRY { - OrtLoggingLevel logging_level = test_config.run_config.f_verbose - ? ORT_LOGGING_LEVEL_VERBOSE - : ORT_LOGGING_LEVEL_WARNING; - - ort_env = std::make_unique(logging_level, "Default"); - } - ORT_CATCH(const Ort::Exception& e) { - ORT_HANDLE_EXCEPTION([&]() { - fprintf(stderr, "Error creating environment. Error-> %s \n", e.what()); - failed = true; - }); - } - - if (failed) - return -1; - } - - ORT_TRY { - SessionOptions so; - so.session_logid = "qnn_ctx_gen_session_logger"; - // Set default session option to dump QNN context model with non-embed mode - CheckStatus(so.config_options.AddConfigEntry(kOrtSessionOptionEpContextEnable, "1")); - CheckStatus(so.config_options.AddConfigEntry(kOrtSessionOptionEpContextEmbedMode, "0")); - RunOptions run_options; - run_options.run_tag = so.session_logid; - - ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif - // set default QNN EP option to enable weight sharing - provider_options["enable_htp_weight_sharing"] = "1"; - - for (auto it : test_config.run_config.qnn_options) { - provider_options[it.first] = it.second; - } - - for (auto it : test_config.run_config.session_config_entries) { - if (it.first == kOrtSessionOptionEpContextEnable && it.second != "1") { - std::cerr << "Need to enable ep context cache." << std::endl; - continue; - } - if (it.first == kOrtSessionOptionEpContextEmbedMode && it.second != "0") { - std::cerr << "Only support non-embed model for weight sharing." << std::endl; - continue; - } - if (it.first == kOrtSessionOptionEpContextFilePath) { - std::cout << "Not support to specify the generated Onnx context cache file name." << std::endl; - continue; - } - CheckStatus(so.config_options.AddConfigEntry(it.first.c_str(), it.second.c_str())); - } - - for (auto model_path : test_config.model_file_paths) { - std::cout << "Model file path: " << ToUTF8String(model_path) << std::endl; - } - - // Generate context cache model files with QNN context binary files - // The context binary file generated later includes all graphs from previous models - { - auto ep = QNNProviderFactoryCreator::Create(provider_options, &so)->CreateProvider(); - std::shared_ptr qnn_ep(std::move(ep)); - - for (auto model_path : test_config.model_file_paths) { - std::cout << "Generate context cache model for: " << ToUTF8String(model_path) << std::endl; - InferenceSession session_object{so, ((OrtEnv*)*ort_env.get())->GetEnvironment()}; - CheckStatus(session_object.RegisterExecutionProvider(qnn_ep)); - CheckStatus(session_object.Load(ToPathString(model_path))); - CheckStatus(session_object.Initialize()); - } - } - - std::cout << "Start to update the generated Onnx model." << std::endl; - std::vector> ep_ctx_files; - ep_ctx_files.reserve(test_config.model_file_paths.size()); - for (auto model_path : test_config.model_file_paths) { - ep_ctx_files.push_back(model_path + ORT_TSTR("_ctx.onnx")); - } - - // Get the last context binary file name - std::string last_qnn_ctx_binary_file_name; - int64_t max_size = 0; - GetLastContextBinaryFileName(ep_ctx_files.back(), last_qnn_ctx_binary_file_name, max_size); - std::cout << "The last context binary file: " << last_qnn_ctx_binary_file_name << std::endl; - if (last_qnn_ctx_binary_file_name.empty()) { - throw Ort::Exception("Can't find QNN context binary file from the Onnx model.", OrtErrorCode::ORT_FAIL); - } - ep_ctx_files.pop_back(); - - // Update generated context cache Onnx model to make the main EPContext node point to - // the last QNN context binary file - // Remove not used QNN context binary file, only keep the last one which contains all graphs - UpdateEpContextModel(ep_ctx_files, last_qnn_ctx_binary_file_name, max_size); - } - ORT_CATCH(const Ort::Exception& e) { - fprintf(stderr, "Failed to generate context cache file: %s \n", e.what()); - - ort_env.reset(); - return -1; - } - - ort_env.reset(); - - return 0; -} - -#ifdef _WIN32 -int wmain(int argc, wchar_t* argv[]) { -#else -int main(int argc, char* argv[]) { -#endif - int retval = -1; - ORT_TRY { - retval = real_main(argc, argv); - } - ORT_CATCH(const std::exception& ex) { - ORT_HANDLE_EXCEPTION([&]() { - fprintf(stderr, "%s\n", ex.what()); - retval = -1; - }); - } - - ::google::protobuf::ShutdownProtobufLibrary(); - - return retval; -} diff --git a/onnxruntime/test/shared_lib/custom_op_utils.cc b/onnxruntime/test/shared_lib/custom_op_utils.cc index bf7efacdbb505..a624479bcd00b 100644 --- a/onnxruntime/test/shared_lib/custom_op_utils.cc +++ b/onnxruntime/test/shared_lib/custom_op_utils.cc @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#include #include "gtest/gtest.h" #include "custom_op_utils.h" @@ -639,3 +640,22 @@ void StandaloneCustomKernel::Compute(OrtKernelContext* context) { StandaloneCustomKernel::~StandaloneCustomKernel() { } + +OrtStatusPtr CustomCastKernel::ComputeV2(OrtKernelContext* context) { + Ort::KernelContext ctx(context); + + auto in = ctx.GetInput(0); + std::vector shape = in.GetTensorTypeAndShapeInfo().GetShape(); + int64_t num_elements = std::accumulate(shape.cbegin(), shape.cend(), int64_t(1), std::multiplies()); + + // CustomCast::GetInputType constraint ensures we only get float input + const float* data = in.GetTensorData(); + double* out_data = ctx.GetOutput(0, shape).GetTensorMutableData(); + gsl::span input_span(data, num_elements); + gsl::span output_span(out_data, num_elements); + + std::transform(input_span.begin(), input_span.end(), output_span.begin(), + [](float val) { return static_cast(val); }); + + return nullptr; +} diff --git a/onnxruntime/test/shared_lib/custom_op_utils.h b/onnxruntime/test/shared_lib/custom_op_utils.h index e11540aaa5691..424c2e2fe3a08 100644 --- a/onnxruntime/test/shared_lib/custom_op_utils.h +++ b/onnxruntime/test/shared_lib/custom_op_utils.h @@ -8,12 +8,6 @@ #include #endif -struct Input { - const char* name = nullptr; - std::vector dims; - std::vector values; -}; - struct MyCustomKernel { MyCustomKernel(const OrtApi& ort_api, const OrtKernelInfo* /*info*/) : ort_(ort_api) { @@ -464,4 +458,63 @@ struct MulTopOpFloat16 : Ort::CustomOpBase OrtCustomOpInputOutputCharacteristic GetInputCharacteristic(size_t) const { return OrtCustomOpInputOutputCharacteristic::INPUT_OUTPUT_OPTIONAL; } -}; \ No newline at end of file +}; + +// +// Example overriding an operator where type inference is required for the output so kernel matching works correctly +// +struct CustomCastKernel { + CustomCastKernel(const OrtApi& /*ort_api*/, const OrtKernelInfo* /*info*/) + /*: ort_(ort_api)*/ { + } + + OrtStatusPtr ComputeV2(OrtKernelContext* context); + + private: + // const OrtApi& ort_; +}; + +// Custom Cast op that takes float input and converts based on 'to' attribute. +// Example implementation only supports cast to double. +struct CustomCast : Ort::CustomOpBase { + explicit CustomCast(const char* provider) : provider_(provider) { + // if overriding an ONNX op you need to set the opset versions you are overriding + start_ver_ = 7; // should match minimum ONNX schema you implement + // end_ver_ = ...; should match maximum ONNX schema you implement or unset for unlimited. + } + + // static method used by Ort::CustomOpBase::SetShapeInferFn + static OrtStatusPtr InferOutputShape(Ort::ShapeInferContext& context) { + auto shape = context.GetInputShape(0); + + // infer output type based on 'to'. + auto to = context.GetAttrInt("to"); + if (to != ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE) { + return Ort::Status("Unexpected type", ORT_INVALID_ARGUMENT).release(); + } + + context.SetOutputShape(0, shape, ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE); + return nullptr; + } + + OrtStatusPtr CreateKernelV2(const OrtApi& api, const OrtKernelInfo* info, void** op_kernel) const { + Ort::ConstKernelInfo ki(info); + *op_kernel = new CustomCastKernel(api, info); + return nullptr; + }; + + const char* GetName() const { return "Cast"; }; + const char* GetExecutionProviderType() const { return provider_; }; + + size_t GetInputTypeCount() const { return 1; }; + ONNXTensorElementDataType GetInputType(size_t /*index*/) const { + // example only accepts float input + return ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT; + }; + + size_t GetOutputTypeCount() const { return 1; }; + ONNXTensorElementDataType GetOutputType(size_t /*index*/) const { return ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED; }; + + private: + const char* provider_{"CPUExecutionProvider"}; +}; diff --git a/onnxruntime/test/shared_lib/test_inference.cc b/onnxruntime/test/shared_lib/test_inference.cc index ca9ca0f82a25a..e00606af1c086 100644 --- a/onnxruntime/test/shared_lib/test_inference.cc +++ b/onnxruntime/test/shared_lib/test_inference.cc @@ -1,17 +1,20 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include -#include -#include -#include -#include +#include #include +#include +#include +#include +#include #include -#include +#include #include +#include #include +#include + #include "gtest/gtest.h" #include "gmock/gmock.h" @@ -25,13 +28,13 @@ #include "core/session/onnxruntime_run_options_config_keys.h" #include "core/util/thread_utils.h" -#include "onnxruntime_config.h" -#include "providers.h" -#include "test_allocator.h" -#include "test_fixture.h" -#include "utils.h" -#include "custom_op_utils.h" -#include +#include "test/shared_lib/custom_op_utils.h" +#include "test/shared_lib/test_fixture.h" +#include "test/shared_lib/utils.h" +#include "test/util/include/providers.h" +#include "test/util/include/test_allocator.h" + +#include "onnxruntime_config.h" // generated file in build output dir #ifdef _WIN32 #include @@ -63,48 +66,6 @@ constexpr size_t countof(T (&)[N]) { return N; } extern std::unique_ptr ort_env; -template -void RunSession(OrtAllocator* allocator, Ort::Session& session_object, - const std::vector& inputs, - const char* output_name, - const std::vector& dims_y, - const std::vector& values_y, - Ort::Value* output_tensor) { - std::vector ort_inputs; - std::vector input_names; - for (size_t i = 0; i < inputs.size(); i++) { - input_names.emplace_back(inputs[i].name); - ort_inputs.emplace_back( - Ort::Value::CreateTensor(allocator->Info(allocator), const_cast(inputs[i].values.data()), - inputs[i].values.size(), inputs[i].dims.data(), inputs[i].dims.size())); - } - - std::vector ort_outputs; - if (output_tensor) - session_object.Run(Ort::RunOptions{nullptr}, input_names.data(), ort_inputs.data(), ort_inputs.size(), - &output_name, output_tensor, 1); - else { - ort_outputs = session_object.Run(Ort::RunOptions{}, input_names.data(), ort_inputs.data(), ort_inputs.size(), - &output_name, 1); - ASSERT_EQ(ort_outputs.size(), 1u); - output_tensor = &ort_outputs[0]; - } - - auto type_info = output_tensor->GetTensorTypeAndShapeInfo(); - ASSERT_EQ(type_info.GetShape(), dims_y); - size_t total_len = type_info.GetElementCount(); - ASSERT_EQ(values_y.size(), total_len); - - OutT* f = output_tensor->GetTensorMutableData(); - for (size_t i = 0; i != total_len; ++i) { - if constexpr (std::is_same::value || std::is_same::value) { - ASSERT_NEAR(values_y[i], f[i], 1e-3); - } else { - ASSERT_EQ(values_y[i], f[i]); - } - } -} - #ifdef USE_DML struct DmlObjects { ComPtr d3d12_device; @@ -300,12 +261,12 @@ Ort::Value CreateTensorValueFromExistingD3DResource( #endif -template +template > static void TestInference(Ort::Env& env, const std::basic_string& model_uri, const std::vector& inputs, const char* output_name, const std::vector& expected_dims_y, - const std::vector& expected_values_y, + const std::vector& expected_values_y, int provider_type, OrtCustomOpDomain* custom_op_domain_ptr, const ORTCHAR_T* custom_op_library_filename, @@ -362,26 +323,26 @@ static void TestInference(Ort::Env& env, const std::basic_string& mod auto default_allocator = std::make_unique(); // without preallocated output tensor - RunSession(default_allocator.get(), - session, - inputs, - output_name, - expected_dims_y, - expected_values_y, - nullptr); + RunSession(default_allocator.get(), + session, + inputs, + output_name, + expected_dims_y, + expected_values_y, + nullptr); // with preallocated output tensor - Ort::Value value_y = Ort::Value::CreateTensor(default_allocator.get(), - expected_dims_y.data(), expected_dims_y.size()); + Ort::Value value_y = Ort::Value::CreateTensor(default_allocator.get(), + expected_dims_y.data(), expected_dims_y.size()); // test it twice for (int i = 0; i != 2; ++i) - RunSession(default_allocator.get(), - session, - inputs, - output_name, - expected_dims_y, - expected_values_y, - &value_y); + RunSession(default_allocator.get(), + session, + inputs, + output_name, + expected_dims_y, + expected_values_y, + &value_y); } } @@ -450,8 +411,8 @@ class CApiTestWithProvider : public testing::Test, public ::testing::WithParamIn TEST_P(CApiTestWithProvider, simple) { // simple inference test // prepare inputs - std::vector inputs(1); - Input& input = inputs.back(); + std::vector> inputs(1); + auto& input = inputs.back(); input.name = "X"; input.dims = {3, 2}; input.values = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; @@ -621,8 +582,8 @@ TEST(CApiTest, SparseInputModel) { TEST(CApiTest, custom_op_handler) { std::cout << "Running custom op inference" << std::endl; - std::vector inputs(1); - Input& input = inputs[0]; + std::vector> inputs(1); + auto& input = inputs[0]; input.name = "X"; input.dims = {3, 2}; input.values = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; @@ -657,8 +618,8 @@ TEST(CApiTest, custom_op_handler) { TEST(CApiTest, custom_op_set_input_memory_type) { std::cout << "Running custom op inference" << std::endl; - std::vector inputs(1); - Input& input = inputs[0]; + std::vector> inputs(1); + auto& input = inputs[0]; input.name = "X"; input.dims = {3, 2}; input.values = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; @@ -687,8 +648,8 @@ TEST(CApiTest, custom_op_set_input_memory_type) { #if !defined(ORT_MINIMAL_BUILD) TEST(CApiTest, StandaloneOpHandler) { - std::vector inputs(1); - Input& input = inputs[0]; + std::vector> inputs(1); + auto& input = inputs[0]; input.name = "X"; input.dims = {3, 2}; input.values = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; @@ -811,7 +772,7 @@ TEST(CApiTest, test_enable_ort_customops_stringlower) { // test custom op which accepts float and double as inputs TEST(CApiTest, varied_input_custom_op_handler) { - std::vector inputs(2); + std::vector> inputs(2); inputs[0].name = "X"; inputs[0].dims = {3}; inputs[0].values = {2.0f, 3.0f, 4.0f}; @@ -1422,8 +1383,8 @@ TEST(CApiTest, custom_op_with_attributes_handler) { TEST(CApiTest, RegisterCustomOpForCPUAndCUDA) { std::cout << "Tests registration of a custom op of the same name for both CPU and CUDA EPs" << std::endl; - std::vector inputs(1); - Input& input = inputs[0]; + std::vector> inputs(1); + auto& input = inputs[0]; input.name = "X"; input.dims = {3, 2}; input.values = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; @@ -1531,7 +1492,7 @@ TEST(CApiTest, test_custom_op_openvino_wrapper_library) { // The custom op extracts the serialized .xml/.bin bytes and creates an in-memory OpenVINO model // during kernel creation. The custom op is passed an image of a hand-drawn "1" as an input during computation, which // is then inferenced using OpenVINO C++ APIs. - std::vector inputs(1); + std::vector> inputs(1); inputs[0].name = "Input3"; inputs[0].dims = {1, 1, 28, 28}; @@ -1630,7 +1591,7 @@ TEST(CApiTest, test_custom_op_library) { #endif std::cout << "Running inference using custom op shared library" << std::endl; - std::vector inputs(2); + std::vector> inputs(2); inputs[0].name = "input_1"; inputs[0].dims = {3, 5}; inputs[0].values = {1.1f, 2.2f, 3.3f, 4.4f, 5.5f, @@ -1682,7 +1643,7 @@ TEST(CApiTest, DISABLED_test_custom_op_shape_infer_attr) { #else TEST(CApiTest, test_custom_op_shape_infer_attr) { #endif - std::vector inputs(1); + std::vector> inputs(1); inputs[0].name = "input_0"; inputs[0].dims = {5}; inputs[0].values = {1.f, 2.f, 3.f, 4.f, 5.f}; @@ -1715,7 +1676,7 @@ TEST(CApiTest, test_custom_op_library_copy_variadic) { #endif std::cout << "Running inference using custom op shared library" << std::endl; - std::vector inputs(2); + std::vector> inputs(2); inputs[0].name = "input_0"; inputs[0].dims = {15}; inputs[0].values = {1.1f, 2.2f, 3.3f, 4.4f, 5.5f, @@ -1869,8 +1830,8 @@ void PrepareModule() { TEST(CApiTest, test_pyop) { std::call_once(my_module_flag, PrepareModule); - std::vector inputs(1); - Input& input = inputs[0]; + std::vector> inputs(1); + auto& input = inputs[0]; input.name = "X"; input.dims = {2, 2}; input.values = {1.0f, 2.0f, 3.0f, 4.0f}; @@ -1882,8 +1843,8 @@ TEST(CApiTest, test_pyop) { TEST(CApiTest, test_pyop_multi) { std::call_once(my_module_flag, PrepareModule); - std::vector inputs(1); - Input& input = inputs[0]; + std::vector> inputs(1); + auto& input = inputs[0]; input.name = "X"; input.dims = {2, 2}; input.values = {1.0f, 2.0f, 3.0f, 4.0f}; @@ -1895,8 +1856,8 @@ TEST(CApiTest, test_pyop_multi) { TEST(CApiTest, test_pyop_kwarg) { std::call_once(my_module_flag, PrepareModule); - std::vector inputs(1); - Input& input = inputs[0]; + std::vector> inputs(1); + auto& input = inputs[0]; input.name = "X"; input.dims = {2, 2}; input.values = {1.0f, 2.0f, 3.0f, 4.0f}; @@ -1920,7 +1881,7 @@ TEST(ReducedOpsBuildTest, test_excluded_ops) { // In reduced ops build, test a model containing ops not included in required_ops.config cannot be loaded. // See onnxruntime/test/testdata/reduced_build_test.readme.txt for more details of the setup constexpr PATH_TYPE model_uri = TSTR("testdata/reduced_build_test.onnx_model_with_excluded_ops"); - std::vector inputs = {{"X", {3}, {-1.0f, 2.0f, -3.0f}}}; + std::vector> inputs = {{"X", {3}, {-1.0f, 2.0f, -3.0f}}}; std::vector expected_dims_y = {3}; std::vector expected_values_y = {0.1f, 0.1f, 0.1f}; bool failed = false; @@ -3322,8 +3283,8 @@ TEST(CApiTest, TestSharedAllocators) { OrtEnv* env_ptr = (OrtEnv*)(*ort_env); // prepare inputs - std::vector inputs(1); - Input& input = inputs.back(); + std::vector> inputs(1); + auto& input = inputs.back(); input.name = "X"; input.dims = {3, 2}; input.values = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; @@ -3509,8 +3470,8 @@ TEST(CApiTest, TestSharedAllocators) { TEST(CApiTest, TestSharingOfInitializerAndItsPrepackedVersion) { // simple inference test // prepare inputs - std::vector inputs(1); - Input& input = inputs.back(); + std::vector> inputs(1); + auto& input = inputs.back(); input.name = "X"; input.dims = {3, 2}; input.values = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; @@ -3905,8 +3866,8 @@ TEST_P(CApiTensorRTTest, TestConfigureTensorRTProviderOptions) { // simple inference test // prepare inputs - std::vector inputs(1); - Input& input = inputs.back(); + std::vector> inputs(1); + auto& input = inputs.back(); input.name = "X"; input.dims = {3, 2}; input.values = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; @@ -4709,6 +4670,34 @@ TEST(CApiTest, RunBaseLoraModel) { } } +TEST(CApiTest, RequestLoadCancellation) { + constexpr const ORTCHAR_T* model_path = ORT_TSTR("testdata/transformers/tiny_gpt2_beamsearch.onnx"); + Ort::Env env(ORT_LOGGING_LEVEL_WARNING); + Ort::SessionOptions session_options; + + auto terminator = [&session_options]() { + session_options.SetLoadCancellationFlag(true); + return; + }; + + std::packaged_task task{terminator}; + std::future terminator_result = task.get_future(); + std::thread terminator_thread{std::move(task)}; + bool terminated = false; + try { + Ort::Session session(env, model_path, session_options); + } catch (const Ort::Exception& ex) { + terminated = OrtErrorCode::ORT_MODEL_LOAD_CANCELED == ex.GetOrtErrorCode(); + } + // done with the thread + terminator_thread.join(); + + // call get to propagate any exception + terminator_result.get(); + + ASSERT_TRUE(terminated); +} + struct MockGQA : public OrtCustomOp { MockGQA() { OrtCustomOp::GetMayInplace = [](int** input_index, int** output_index) { @@ -4845,4 +4834,32 @@ TEST(CApiTest, GenerateNodeStatsFile) { output_names, 1); } -#endif \ No newline at end of file +#endif + +// Test that creates a custom Cast kernel which requires type inference of the output type to work. +// Also demonstrates overriding an ONNX operator as we register the custom op in the ONNX domain. +TEST(CApiTest, custom_cast) { + std::vector> inputs(1); + auto& input = inputs[0]; + input.name = "input"; + input.dims = {3, 4}; + input.values = {1.0f, 2.0f, 3.0f, 4.0f, + -1.0f, -2.0f, -3.0f, -4.0f, + 1.0f, 2.0f, 3.0f, 4.0f}; + + // prepare expected inputs and outputs + std::vector expected_dims_y = {3, 4}; + std::vector expected_values_y = {1.0, 2.0, 3.0, 4.0, + -1.0, -2.0, -3.0, -4.0, + 1.0, 2.0, 3.0, 4.0}; + + CustomCast custom_op{onnxruntime::kCpuExecutionProvider}; + + Ort::CustomOpDomain custom_op_domain(""); // onnx domain is empty string + custom_op_domain.Add(&custom_op); + + // model with Cast from ONNX test data + TestInference(*ort_env, TSTR("testdata/cast_float_to_double.onnx"), + inputs, "output", expected_dims_y, expected_values_y, 0, + custom_op_domain, nullptr); +} diff --git a/onnxruntime/test/shared_lib/test_model_builder_api.cc b/onnxruntime/test/shared_lib/test_model_builder_api.cc new file mode 100644 index 0000000000000..9807fcca06ed4 --- /dev/null +++ b/onnxruntime/test/shared_lib/test_model_builder_api.cc @@ -0,0 +1,701 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include + +#include "gtest/gtest.h" +#include "gmock/gmock.h" + +#include "core/common/narrow.h" +#include "core/graph/constants.h" +#include "core/session/onnxruntime_c_api.h" +#include "core/session/onnxruntime_cxx_api.h" +#include "core/session/onnxruntime_lite_custom_op.h" +#include "core/session/onnxruntime_session_options_config_keys.h" + +#include "test/shared_lib/test_fixture.h" +#include "test/shared_lib/utils.h" +#include "test/util/include/test_allocator.h" + +#include "onnxruntime_config.h" // generated file in build output dir + +extern std::unique_ptr ort_env; + +using namespace Ort; + +namespace { + +Ort::Session CreateSession(Ort::Env& env, + Model& graph_api_model, + Ort::SessionOptions* session_options_for_test = nullptr) { + Ort::SessionOptions default_session_options; + Ort::SessionOptions& session_options = session_options_for_test ? *session_options_for_test + : default_session_options; + + // Set this to save the model if you want to debug. + // session_options.SetOptimizedModelFilePath(ORT_TSTR("model_builder_output.onnx")); + + Ort::Session session(env, graph_api_model, session_options); + + // Session should not require the model to stay alive so free it now to validate. + graph_api_model = Model(nullptr); + + return session; +} + +template +void TestInference(Ort::Session& session, + const std::vector>& inputs, + const char* output_name, + const std::vector& expected_dims, + const std::vector& expected_values) { + auto default_allocator = std::make_unique(); + + // without preallocated output tensor + RunSession(default_allocator.get(), + session, + inputs, + output_name, + expected_dims, + expected_values, + nullptr); +} + +// Create OrtNode using the C API +OrtNode* CreateNode(const OrtModelEditorApi& api, + const char* operator_name, const char* node_name, + const gsl::span input_names, + const gsl::span output_names, + const gsl::span attributes = {}, + const char* domain_name = onnxruntime::kOnnxDomain) { + OrtNode* node = nullptr; + Ort::ThrowOnError(api.CreateNode(operator_name, domain_name, node_name, + input_names.data(), input_names.size(), + output_names.data(), output_names.size(), + attributes.data(), attributes.size(), + &node)); + return node; +} + +// convenience func to convert initalizer lists to gsl::span +OrtNode* CreateNode(const OrtModelEditorApi& api, + const char* operator_name, const char* node_name, + const std::initializer_list input_names, + const std::initializer_list output_names, + const std::initializer_list attributes = {}, + const char* domain_name = onnxruntime::kOnnxDomain) { + std::vector inputs(input_names); + std::vector outputs(output_names); + std::vector attrs(attributes); + return CreateNode(api, operator_name, node_name, inputs, outputs, attrs, domain_name); +} +} // namespace + +struct TestAllocator : public OrtAllocator { + TestAllocator() { + version = ORT_API_VERSION; + Info = [](const struct OrtAllocator* this_ptr) -> const struct OrtMemoryInfo* { + auto* test_allocator = static_cast(this_ptr); + return test_allocator->memory_info; + }; + + Free = [](struct OrtAllocator* allocator, void* p) -> void { + auto* test_allocator = static_cast(allocator); + // find the matching pointer and remove it + auto it = std::find_if(test_allocator->weights.begin(), test_allocator->weights.end(), + [p](const std::unique_ptr>& v) { return v->data() == p; }); + if (it == test_allocator->weights.end()) { + throw std::runtime_error("Free called with unknown pointer"); + } + + test_allocator->weights.erase(it); + }; + + Alloc = [](struct OrtAllocator* /*this*/, size_t /*size*/) -> void* { + throw std::runtime_error("This should not be used"); + }; + + Reserve = [](struct OrtAllocator* /*this*/, size_t /*size*/) -> void* { + throw std::runtime_error("This should not be used"); + }; + } + + // initializers that are used directly by the model. as there's no copy they must remain valid. + // we store them in the test allocator so we can validate that Free is called + std::vector>> weights; + Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtDeviceAllocator, + OrtMemType::OrtMemTypeDefault); +}; + +// Test the ModelEditorAPI C api +// Uses the ORT C++ api for the rest for simplicity +TEST(ModelEditorAPITest, Basic_CApi) { + const auto& api = Ort::GetApi(); + const auto& model_editor_api = Ort::GetModelEditorApi(); + + TestAllocator deleter; + + // return void so we can use ASSERT_* in the lambda + const auto build_model = [&](bool use_constant_node, OrtModel*& model) -> void { + OrtGraph* graph = nullptr; + Ort::ThrowOnError(model_editor_api.CreateGraph(&graph)); + + // + // Create OrtModel with a Gemm. X input is 3x4, Y input is 4x8, Z output is 3x8. + // X is model input. Y is initializer. + // Set the alpha attribute of the Gemm node to 2.0 to test attribute handling. + // + + // model input + OrtTensorTypeAndShapeInfo* tensor_type_info = nullptr; + std::vector input_dims = {3, 4}; + // can use api.SetSymbolicDimensions to set symbolic dimensions. + // the input array should have the same rank as the call to SetDimensions. + // e.g. call SetDimensions with {-1, 3, 2} and SetSymbolicDimensions with {"N", nullptr, nullptr} to create + // a shape of {"N", 3, 2} + + Ort::ThrowOnError(api.CreateTensorTypeAndShapeInfo(&tensor_type_info)); + Ort::ThrowOnError(api.SetTensorElementType(tensor_type_info, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT)); + Ort::ThrowOnError(api.SetDimensions(tensor_type_info, input_dims.data(), input_dims.size())); + + OrtTypeInfo* input_type_info = nullptr; + Ort::ThrowOnError(model_editor_api.CreateTensorTypeInfo(tensor_type_info, &input_type_info)); + api.ReleaseTensorTypeAndShapeInfo(tensor_type_info); // input_type_info took a copy + + // create ValueInfo and release the type info as CreateValueInfo takes a copy. + OrtValueInfo* input_value_info = nullptr; + Ort::ThrowOnError(model_editor_api.CreateValueInfo("X", input_type_info, &input_value_info)); + api.ReleaseTypeInfo(input_type_info); // input_value_info took a copy + tensor_type_info = nullptr; + + // model outputs + OrtTypeInfo* output_type_info = nullptr; + std::vector output_dims = {3, 8}; + + Ort::ThrowOnError(api.CreateTensorTypeAndShapeInfo(&tensor_type_info)); + Ort::ThrowOnError(api.SetTensorElementType(tensor_type_info, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT)); + Ort::ThrowOnError(api.SetDimensions(tensor_type_info, output_dims.data(), output_dims.size())); + + Ort::ThrowOnError(model_editor_api.CreateTensorTypeInfo(tensor_type_info, &output_type_info)); + api.ReleaseTensorTypeAndShapeInfo(tensor_type_info); // input_type_info took a copy + + OrtValueInfo* output_value_info = nullptr; + Ort::ThrowOnError(model_editor_api.CreateValueInfo("Z", output_type_info, &output_value_info)); + api.ReleaseTypeInfo(output_type_info); + + std::vector graph_inputs = {input_value_info}; + std::vector graph_outputs = {output_value_info}; + Ort::ThrowOnError(model_editor_api.SetGraphInputs(graph, graph_inputs.data(), graph_inputs.size())); + Ort::ThrowOnError(model_editor_api.SetGraphOutputs(graph, graph_outputs.data(), graph_outputs.size())); + input_value_info = nullptr; // graph now owns the input/output values + output_value_info = nullptr; + + // + // Gemm node + // + + OrtOpAttr* alpha_attr = nullptr; + float alpha_value = 2.0; + Ort::ThrowOnError(api.CreateOpAttr("alpha", &alpha_value, 1, OrtOpAttrType::ORT_OP_ATTR_FLOAT, &alpha_attr)); + + std::vector node_input_names = {"X", "Y"}; + const std::string gemm_output_name = use_constant_node ? "Z_temp" : "Z"; + std::vector node_output_names = {gemm_output_name.c_str()}; + std::vector node_attributes{alpha_attr}; + OrtNode* node = CreateNode(model_editor_api, "Gemm", "Gemm1", node_input_names, node_output_names, node_attributes); + alpha_attr = nullptr; // Node now owns + + Ort::ThrowOnError(model_editor_api.AddNodeToGraph(graph, node)); + node = nullptr; // graph now owns node + + // Y input + // As it's 128 bytes it could either be allocated using CreateTensorAsOrtValue or use existing memory. + // Under 128 bytes must use CreateTensorAsOrtValue. + std::vector y_dims = {4, 8}; + + deleter.weights.emplace_back(std::make_unique>(32)); + auto& y_values = *deleter.weights.back(); + std::iota(y_values.begin(), y_values.end(), 1.0f); + + // create an initializer for the Y input. add to `weights` so the memory remains valid. + OrtValue* y_tensor = nullptr; + Ort::ThrowOnError( + api.CreateTensorWithDataAndDeleterAsOrtValue(&deleter, + y_values.data(), y_values.size() * sizeof(y_values[0]), + y_dims.data(), y_dims.size(), + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, + &y_tensor)); + + Ort::ThrowOnError(model_editor_api.AddInitializerToGraph(graph, "Y", y_tensor, /*data is external*/ true)); + y_tensor = nullptr; // graph now owns + + if (use_constant_node) { + // Test that a Constant node is converted to an initializer + + // create Constant nodes for min/max to limit output range + OrtOpAttr* min_attr = nullptr; + float min = 400.0f; + Ort::ThrowOnError(api.CreateOpAttr("value", &min, sizeof(min), ORT_OP_ATTR_FLOAT, &min_attr)); + node = CreateNode(model_editor_api, "Constant", "clip_min", {}, {"min"}, {min_attr}); + Ort::ThrowOnError(model_editor_api.AddNodeToGraph(graph, node)); + node = nullptr; // graph now owns node + + OrtOpAttr* max_attr = nullptr; + float max = 900.0f; + Ort::ThrowOnError(api.CreateOpAttr("value", &max, sizeof(max), ORT_OP_ATTR_FLOAT, &max_attr)); + node = CreateNode(model_editor_api, "Constant", "clip_max", {}, {"max"}, {max_attr}); + Ort::ThrowOnError(model_editor_api.AddNodeToGraph(graph, node)); + node = nullptr; // graph now owns node + + node = CreateNode(model_editor_api, "Clip", "Clip1", {gemm_output_name.c_str(), "min", "max"}, {"Z"}); + Ort::ThrowOnError(model_editor_api.AddNodeToGraph(graph, node)); + node = nullptr; // graph now owns node + } + + std::vector domain_names = {onnxruntime::kOnnxDomain}; + std::vector opset_versions = {18}; + Ort::ThrowOnError(model_editor_api.CreateModel(domain_names.data(), opset_versions.data(), domain_names.size(), + &model)); + Ort::ThrowOnError(model_editor_api.AddGraphToModel(model, graph)); + graph = nullptr; // model now owns + }; + + auto run_test = [&](bool use_constant_node) -> void { + OrtModel* model = nullptr; + build_model(use_constant_node, model); + + ASSERT_NE(model, nullptr) << "build_model should have created a model"; + + std::vector> inputs(1); + auto& input = inputs[0]; + input.name = "X"; + input.dims = {3, 4}; + input.values = {1.0f, 2.0f, 3.0f, 4.0f, + 8.0f, 7.0f, 6.0f, 5.0f, + 9.0f, 3.0f, 5.0f, 7.0f}; + + std::vector expected_dims = {3, 8}; + Model cxx_model(model); + auto session = CreateSession(*ort_env, cxx_model); + + std::vector expected_output; + if (use_constant_node) { + // clipped with min 400 and max 900 + expected_output = {400.0f, 400.0f, 400.0f, 400.0f, 420.0f, 440.0f, 460.0f, 480.0f, + 596.0f, 648.0f, 700.0f, 752.0f, 804.0f, 856.0f, 900.0f, 900.0f, + 592.0f, 640.0f, 688.0f, 736.0f, 784.0f, 832.0f, 880.0f, 900.0f}; + } else { + expected_output = {340.0f, 360.0f, 380.0f, 400.0f, 420.0f, 440.0f, 460.0f, 480.0f, + 596.0f, 648.0f, 700.0f, 752.0f, 804.0f, 856.0f, 908.0f, 960.0f, + 592.0f, 640.0f, 688.0f, 736.0f, 784.0f, 832.0f, 880.0f, 928.0f}; + } + + TestInference(session, inputs, "Z", expected_dims, expected_output); + + api.ReleaseSession(session.release()); + + ASSERT_EQ(deleter.weights.size(), size_t(0)) << "All weights should have been freed"; + }; + + run_test(false); + run_test(true); // use Constant node for initializer +} + +TEST(ModelEditorAPITest, Basic_CxxApi) { + // initializers that are used directly by the model. as there's no copy they must remain valid + std::vector>> weights; + + Ort::Graph graph; + + // + // Create OrtModel with a Gemm. X input is 3x4, Y input is 4x8, Z output is 3x8. + // X is model input. Y is initializer. + // Set the alpha attribute of the Gemm node to 2.0 to test attribute handling. + // + + std::vector graph_inputs; + std::vector graph_outputs; + + // model input. it's {3, 4} but use a symbolic dim to test that works. + std::vector input_dims({-1, 4}); + std::vector input_symbolic_dims({"multiple_of_3", ""}); + TensorTypeAndShapeInfo input_tensor_info(ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, + input_dims, + &input_symbolic_dims); + auto input_type_info = TypeInfo::CreateTensorInfo(input_tensor_info.GetConst()); + graph_inputs.emplace_back("X", input_type_info.GetConst()); + + // model outputs + std::vector output_dims = {-1, 8}; + std::vector output_symbolic_dims({"multiple_of_3", ""}); + TensorTypeAndShapeInfo output_tensor_info(ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, + output_dims, + &output_symbolic_dims); + auto output_type_info = TypeInfo::CreateTensorInfo(output_tensor_info.GetConst()); + graph_outputs.emplace_back("Z", output_type_info.GetConst()); + + graph.SetInputs(graph_inputs); + graph.SetOutputs(graph_outputs); + + // + // Gemm node + // + + std::vector attributes; + float alpha_value = 2.0; + attributes.push_back(OpAttr("alpha", &alpha_value, 1, OrtOpAttrType::ORT_OP_ATTR_FLOAT)); + + Node node("Gemm", onnxruntime::kOnnxDomain, "Gemm1", {"X", "Y"}, {"Z"}, attributes); + + graph.AddNode(node); + + // create an initializer for the Y input. + // add to `weights` so it remains valid for the lifetime of the session and we can avoid copying the data. + // As it's 128 bytes it could either be allocated using CreateTensorAsOrtValue or use existing memory. + // Under 128 bytes must use CreateTensorAsOrtValue. + std::vector y_dims = {4, 8}; + + weights.emplace_back(std::make_unique>(32)); + auto& y_values = *weights.back(); + std::iota(y_values.begin(), y_values.end(), 1.0f); + + auto info = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeDefault); + + // if you use this API the initializer data MUST remain valid for the lifetime of the InferenceSession + auto y_tensor = Value::CreateTensor(info, y_values.data(), y_values.size(), y_dims.data(), y_dims.size()); + graph.AddInitializer("Y", y_tensor, /*data is external*/ true); + + std::vector opsets{{onnxruntime::kOnnxDomain, 18}}; + Model model(opsets); + model.AddGraph(graph); + + std::vector> inputs(1); + auto& input = inputs[0]; + input.name = "X"; + input.dims = {3, 4}; + input.values = {1.0f, 2.0f, 3.0f, 4.0f, + 8.0f, 7.0f, 6.0f, 5.0f, + 9.0f, 3.0f, 5.0f, 7.0f}; + + std::vector expected_dims = {3, 8}; + + auto session = CreateSession(*ort_env, model); + TestInference(session, inputs, "Z", expected_dims, + {340.0f, 360.0f, 380.0f, 400.0f, 420.0f, 440.0f, 460.0f, 480.0f, + 596.0f, 648.0f, 700.0f, 752.0f, 804.0f, 856.0f, 908.0f, 960.0f, + 592.0f, 640.0f, 688.0f, 736.0f, 784.0f, 832.0f, 880.0f, 928.0f}); +} + +TEST(ModelEditorAPITest, BasicModelEdit_CxxApi) { + // + // Load existing model + // Add Cast to change the model input from float to int64 + // Update model inputs to match + // Run + // + + SessionOptions so; + + // Set this to save the model if you want to debug. + // so.SetOptimizedModelFilePath(ORT_TSTR("model_builder_edited.onnx")); + + Session session = Session::CreateModelEditorSession(*ort_env, TSTR("testdata/mnist.onnx"), so); + + ASSERT_EQ(session.GetOpset(""), 8); // ONNX domain is empty string + + // we augment the original model with nodes, initializers and the updated model inputs/outputs from this model. + // the original graph is unchanged. nodes can be added before/after it. initializers can be added. + // new nodes must conform to the original domain:opset of the model. + // additional operator domain:opset pairs can be added. + std::vector opsets; // no additional opsets required + Model model(opsets); + + std::vector graph_inputs = session.GetInputs(); + ASSERT_EQ(graph_inputs.size(), size_t(1)); + ASSERT_EQ(graph_inputs[0].TypeInfo().GetTensorTypeAndShapeInfo().GetElementType(), + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT); + + // typically this isn't needed. we replace this input but need to read info from it later on in the test + // validation so we save the info locally to keep it accessible. + auto orig_input_name = graph_inputs[0].Name(); + auto input_shape = graph_inputs[0].TypeInfo().GetTensorTypeAndShapeInfo().GetShape(); + const std::string new_input_name = "Int64Input"; + + // Add Cast node to convert input from float to int64 + std::vector attributes; + int64_t to = ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT; + attributes.push_back(OpAttr("to", &to, 1, OrtOpAttrType::ORT_OP_ATTR_INT)); + + Ort::Node node("Cast", onnxruntime::kOnnxDomain, new_input_name, {"Int64Input"}, + // the existing node will now consume the output from the Cast instead of a graph input + {orig_input_name}, + attributes); + + // we're replacing the only input. the shape is the same but the name and data type change. + TensorTypeAndShapeInfo input_tensor_info(ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64, + input_shape); + auto input_type_info = TypeInfo::CreateTensorInfo(input_tensor_info.GetConst()); + graph_inputs[0] = ValueInfo(new_input_name, input_type_info.GetConst()); + + Graph graph; // new info to augment the model with + + graph.AddNode(node); + graph.SetInputs(graph_inputs); + + // the node we added does not require any new opsets. + model.AddGraph(graph); + session.FinalizeModelEditorSession(model, so); + + std::vector> inputs(1); + auto& input = inputs[0]; + input.name = new_input_name.c_str(); + input.dims = input_shape; + + auto num_values = std::accumulate(input.dims.begin(), input.dims.end(), int64_t(1), std::multiplies()); + input.values.resize(size_t(num_values)); + std::iota(input.values.begin(), input.values.end(), 1); + + std::vector expected_dims = {1, 10}; + std::vector expected_output = {-48.5088f, -1040.2948f, -347.0959f, 101.7392f, 421.3352f, + 750.92145f, 231.5060f, -1694.4152f, 681.5623f, 378.1689f}; + + TestInference(session, inputs, session.GetOutputNames()[0].c_str(), expected_dims, expected_output); + + // double check with original model + { + SessionOptions expected_so; + Session expected_session = Session(*ort_env, TSTR("testdata/mnist.onnx"), expected_so); + std::vector> expected_inputs(1); + auto& expected_input = expected_inputs[0]; + expected_input.name = orig_input_name.c_str(); + expected_input.dims = input_shape; + expected_input.values.reserve(size_t(num_values)); + std::transform(input.values.begin(), input.values.end(), std::back_inserter(expected_input.values), + [&](int64_t value) { return float(value); }); + + TestInference(expected_session, expected_inputs, session.GetOutputNames()[0].c_str(), + expected_dims, expected_output); + } +} + +TEST(ModelEditorAPITest, InvalidDimension) { + try { + std::vector input_dims = {-2, 2}; + TensorTypeAndShapeInfo tensor_type_info(ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, + input_dims); + // invalid dim of -2 should cause exception + TypeInfo::CreateTensorInfo(tensor_type_info.GetConst()); + FAIL() << "Expected exception for invalid dimension"; + } catch (const Ort::Exception& e) { + ASSERT_STREQ(e.what(), "dim_values must be -1 (symbolic dimension) or larger."); + } +} + +TEST(ModelEditorAPITest, CreateInvalidModel_NoOpsets) { + Ort::Graph graph; + std::vector graph_inputs; + std::vector graph_outputs; + + std::vector dims({4}); + TensorTypeAndShapeInfo tensor_info(ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, dims); + auto type_info = TypeInfo::CreateTensorInfo(tensor_info.GetConst()); + graph_inputs.emplace_back("X", type_info.GetConst()); + graph_outputs.emplace_back("Z", type_info.GetConst()); + + graph.SetInputs(graph_inputs); + graph.SetOutputs(graph_outputs); + + Ort::Node node("Add", onnxruntime::kOnnxDomain, "Add1", {"X", "X"}, {"Z"}); + + graph.AddNode(node); + + std::vector opsets; + Model model(opsets); + model.AddGraph(graph); + + try { + auto session = CreateSession(*ort_env, model); + FAIL(); + } catch (const Ort::Exception& e) { + ASSERT_THAT(e.what(), ::testing::HasSubstr("Error No opset import for domain")); + } +} + +TEST(ModelEditorAPITest, CreateInvalidModel_MissingValue) { + Ort::Graph graph; + + std::vector graph_inputs; + std::vector graph_outputs; + + std::vector dims({4}); + TensorTypeAndShapeInfo tensor_info(ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, dims); + auto type_info = TypeInfo::CreateTensorInfo(tensor_info.GetConst()); + graph_inputs.emplace_back("X", type_info.GetConst()); + graph_outputs.emplace_back("Z", type_info.GetConst()); + + graph.SetInputs(graph_inputs); + graph.SetOutputs(graph_outputs); + + Ort::Node node("Add", onnxruntime::kOnnxDomain, "Add1", {"X", "missing"}, {"Z"}); + graph.AddNode(node); + + std::vector opsets{{onnxruntime::kOnnxDomain, 18}}; + Model model(opsets); + model.AddGraph(graph); + + try { + auto session = CreateSession(*ort_env, model); + FAIL(); + } catch (const Ort::Exception& e) { + ASSERT_THAT(e.what(), ::testing::HasSubstr("Node input 'missing' is not a graph input, " + "initializer, or output of a previous node.")); + } +} + +TEST(ModelEditorAPITest, InvalidModelEdit) { + // Add a node but make the edit invalid in various ways + // - add node but don't update graph inputs + // - add node with invalid domain + const auto edit_model = [](bool invalid_domain) { + SessionOptions so; + + // Set this to save the model if you want to debug. + // so.SetOptimizedModelFilePath(ORT_TSTR("model_builder_edited.onnx")); + + Session session = Session::CreateModelEditorSession(*ort_env, TSTR("testdata/mnist.onnx"), so); + + ASSERT_EQ(session.GetOpset(""), 8); // ONNX domain is empty string + + std::vector opsets; // no additional opsets required + Model model(opsets); + Graph graph; // new info to augment the model with + + const char* domain = invalid_domain ? "invalid_domain" : onnxruntime::kOnnxDomain; + + std::vector graph_inputs = session.GetInputs(); + ASSERT_EQ(graph_inputs.size(), size_t(1)); + ASSERT_EQ(graph_inputs[0].TypeInfo().GetTensorTypeAndShapeInfo().GetElementType(), + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT); + + const std::string new_input_name = "Int64Input"; + + // Add Cast node to convert input from float to int64 + std::vector attributes; + int64_t to = ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT; + attributes.push_back(OpAttr("to", &to, 1, OrtOpAttrType::ORT_OP_ATTR_INT)); + + Node node("Cast", domain, "NewInputNode", {new_input_name}, + // the existing node will now consume the output from the Cast instead of a graph input + {graph_inputs[0].Name()}, + attributes); + graph.AddNode(node); + + if (invalid_domain) { + // we're replacing the only input. the shape is the same but the name and data type change. + TensorTypeAndShapeInfo input_tensor_info(ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64, + graph_inputs[0].TypeInfo().GetTensorTypeAndShapeInfo().GetShape()); + auto input_type_info = TypeInfo::CreateTensorInfo(input_tensor_info.GetConst()); + graph_inputs[0] = ValueInfo(new_input_name, input_type_info.GetConst()); + graph.SetInputs(graph_inputs); + } else { + // model should be invalid as we didn't connect the new node up to the graph inputs + } + + // the node we added does not require any new opsets. + model.AddGraph(graph); + + try { + session.FinalizeModelEditorSession(model, so); + FAIL() << "Should have failed to resolve graph due to invalid edits."; + } catch (const Ort::Exception& e) { + if (invalid_domain) { + ASSERT_THAT(e.what(), ::testing::HasSubstr("Error No opset import for domain 'invalid_domain'")); + } else { + ASSERT_THAT(e.what(), ::testing::HasSubstr("This is an invalid model")); + } + } + }; + + edit_model(false); + edit_model(true); // add node with invalid domain +} + +TEST(ModelEditorAPITest, CreateTypeInfo) { + const auto& api = Ort::GetApi(); + const auto& model_editor_api = Ort::GetModelEditorApi(); + + TensorTypeAndShapeInfo base_tensor_info(ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, + {2, 4}); + + OrtTypeInfo* base_tensor_type_info = nullptr; + Ort::ThrowOnError(model_editor_api.CreateTensorTypeInfo(base_tensor_info, &base_tensor_type_info)); + + ONNXType onnx_type = ONNX_TYPE_UNKNOWN; + const OrtTensorTypeAndShapeInfo* tensor_info = nullptr; + ONNXTensorElementDataType onnx_element_type = ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED; + + // sparse tensor + OrtTypeInfo* sparse_tensor_type_info = nullptr; + Ort::ThrowOnError(model_editor_api.CreateSparseTensorTypeInfo(base_tensor_info, &sparse_tensor_type_info)); + Ort::ThrowOnError(api.GetOnnxTypeFromTypeInfo(sparse_tensor_type_info, &onnx_type)); + ASSERT_EQ(onnx_type, ONNXType::ONNX_TYPE_SPARSETENSOR); + Ort::ThrowOnError(api.CastTypeInfoToTensorInfo(sparse_tensor_type_info, &tensor_info)); + Ort::ThrowOnError(api.GetTensorElementType(tensor_info, &onnx_element_type)); + ASSERT_EQ(onnx_element_type, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT); + api.ReleaseTypeInfo(sparse_tensor_type_info); + + // sequence + OrtTypeInfo* sequence_type_info = nullptr; + const OrtSequenceTypeInfo* sequence_info = nullptr; + OrtTypeInfo* sequence_element_type_info = nullptr; + + Ort::ThrowOnError(model_editor_api.CreateSequenceTypeInfo(base_tensor_type_info, &sequence_type_info)); + Ort::ThrowOnError(api.GetOnnxTypeFromTypeInfo(sequence_type_info, &onnx_type)); + ASSERT_EQ(onnx_type, ONNXType::ONNX_TYPE_SEQUENCE); + Ort::ThrowOnError(api.CastTypeInfoToSequenceTypeInfo(sequence_type_info, &sequence_info)); + Ort::ThrowOnError(api.GetSequenceElementType(sequence_info, &sequence_element_type_info)); + Ort::ThrowOnError(api.GetOnnxTypeFromTypeInfo(sequence_element_type_info, &onnx_type)); + ASSERT_EQ(onnx_type, ONNXType::ONNX_TYPE_TENSOR); + Ort::ThrowOnError(api.CastTypeInfoToTensorInfo(sequence_element_type_info, &tensor_info)); + Ort::ThrowOnError(api.GetTensorElementType(tensor_info, &onnx_element_type)); + ASSERT_EQ(onnx_element_type, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT); + api.ReleaseTypeInfo(sequence_element_type_info); + api.ReleaseTypeInfo(sequence_type_info); + + // map + OrtTypeInfo* map_type_info = nullptr; + const OrtMapTypeInfo* map_info = nullptr; + ONNXTensorElementDataType map_key_type = ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED; + OrtTypeInfo* map_value_type_info = nullptr; + Ort::ThrowOnError(model_editor_api.CreateMapTypeInfo(ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64, base_tensor_type_info, + &map_type_info)); // clones map_type_info + Ort::ThrowOnError(api.GetOnnxTypeFromTypeInfo(map_type_info, &onnx_type)); + ASSERT_EQ(onnx_type, ONNXType::ONNX_TYPE_MAP); + Ort::ThrowOnError(api.CastTypeInfoToMapTypeInfo(map_type_info, &map_info)); + Ort::ThrowOnError(api.GetMapKeyType(map_info, &map_key_type)); + ASSERT_EQ(map_key_type, ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64); + Ort::ThrowOnError(api.GetMapValueType(map_info, &map_value_type_info)); + Ort::ThrowOnError(api.GetOnnxTypeFromTypeInfo(map_value_type_info, &onnx_type)); + ASSERT_EQ(onnx_type, ONNXType::ONNX_TYPE_TENSOR); + Ort::ThrowOnError(api.CastTypeInfoToTensorInfo(map_value_type_info, &tensor_info)); + Ort::ThrowOnError(api.GetTensorElementType(tensor_info, &onnx_element_type)); + ASSERT_EQ(onnx_element_type, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT); + api.ReleaseTypeInfo(map_value_type_info); + api.ReleaseTypeInfo(map_type_info); + + // optional + OrtTypeInfo* optional_type_info = nullptr; + const OrtOptionalTypeInfo* optional_info = nullptr; + OrtTypeInfo* optional_contained_type_info = nullptr; + Ort::ThrowOnError(model_editor_api.CreateOptionalTypeInfo(base_tensor_type_info, &optional_type_info)); + Ort::ThrowOnError(api.GetOnnxTypeFromTypeInfo(optional_type_info, &onnx_type)); + ASSERT_EQ(onnx_type, ONNXType::ONNX_TYPE_OPTIONAL); + Ort::ThrowOnError(api.CastTypeInfoToOptionalTypeInfo(optional_type_info, &optional_info)); + Ort::ThrowOnError(api.GetOptionalContainedTypeInfo(optional_info, &optional_contained_type_info)); + Ort::ThrowOnError(api.GetOnnxTypeFromTypeInfo(optional_contained_type_info, &onnx_type)); + ASSERT_EQ(onnx_type, ONNXType::ONNX_TYPE_TENSOR); + api.ReleaseTypeInfo(optional_contained_type_info); + api.ReleaseTypeInfo(optional_type_info); + + api.ReleaseTypeInfo(base_tensor_type_info); +} diff --git a/onnxruntime/test/shared_lib/test_ort_format_models.cc b/onnxruntime/test/shared_lib/test_ort_format_models.cc index 99a9ebc3362ae..b3491e3476f23 100644 --- a/onnxruntime/test/shared_lib/test_ort_format_models.cc +++ b/onnxruntime/test/shared_lib/test_ort_format_models.cc @@ -17,7 +17,7 @@ extern std::unique_ptr ort_env; [[maybe_unused]] static void TestInference(Ort::Env& env, const std::basic_string& model_uri, - const std::vector& inputs, const char* output_name, + const std::vector>& inputs, const char* output_name, const std::vector& expected_dims_y, const std::vector& expected_values_y, Ort::CustomOpDomain& custom_op_domain, void* cuda_compute_stream = nullptr) { Ort::SessionOptions session_options; @@ -100,8 +100,8 @@ TEST(OrtFormatCustomOpTests, ConvertOnnxModelToOrt) { } // now load the ORT format model and execute it - std::vector inputs(1); - Input& input = inputs[0]; + std::vector> inputs(1); + auto& input = inputs[0]; input.name = "X"; input.dims = {3, 2}; input.values = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; @@ -130,8 +130,8 @@ TEST(OrtFormatCustomOpTests, LoadOrtModel) { custom_op_domain.Add(&custom_op); // load the ORT format model and execute it - std::vector inputs(1); - Input& input = inputs[0]; + std::vector> inputs(1); + auto& input = inputs[0]; input.name = "X"; input.dims = {3, 2}; input.values = {6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f}; @@ -151,8 +151,8 @@ TEST(OrtFormatCustomOpTests, LoadOrtModelStandaloneCustomOpImplementation) { custom_op_domain.Add(&standalone_op); // load the ORT format model and execute it - std::vector inputs(1); - Input& input = inputs[0]; + std::vector> inputs(1); + auto& input = inputs[0]; input.name = "X"; input.dims = {3, 2}; input.values = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; diff --git a/onnxruntime/test/shared_lib/utils.h b/onnxruntime/test/shared_lib/utils.h index 483753f2ae6b2..5d15582b86cb9 100644 --- a/onnxruntime/test/shared_lib/utils.h +++ b/onnxruntime/test/shared_lib/utils.h @@ -5,4 +5,56 @@ #include "core/session/onnxruntime_cxx_api.h" +#include "gtest/gtest.h" + OrtCUDAProviderOptions CreateDefaultOrtCudaProviderOptionsWithCustomStream(void* cuda_compute_stream = nullptr); + +template +struct Input { + const char* name = nullptr; + std::vector dims; + std::vector values; +}; + +template > +void RunSession(OrtAllocator* allocator, + Ort::Session& session_object, + const std::vector& inputs, + const char* output_name, + const std::vector& output_dims, + const std::vector& expected_output, + Ort::Value* output_tensor) { + std::vector ort_inputs; + std::vector input_names; + for (size_t i = 0; i < inputs.size(); i++) { + input_names.emplace_back(inputs[i].name); + ort_inputs.emplace_back( + Ort::Value::CreateTensor(allocator->Info(allocator), const_cast(inputs[i].values.data()), + inputs[i].values.size(), inputs[i].dims.data(), inputs[i].dims.size())); + } + + std::vector ort_outputs; + if (output_tensor) + session_object.Run(Ort::RunOptions{nullptr}, input_names.data(), ort_inputs.data(), ort_inputs.size(), + &output_name, output_tensor, 1); + else { + ort_outputs = session_object.Run(Ort::RunOptions{}, input_names.data(), ort_inputs.data(), ort_inputs.size(), + &output_name, 1); + ASSERT_EQ(ort_outputs.size(), 1u); + output_tensor = &ort_outputs[0]; + } + + auto type_info = output_tensor->GetTensorTypeAndShapeInfo(); + ASSERT_EQ(type_info.GetShape(), output_dims); + size_t total_len = type_info.GetElementCount(); + ASSERT_EQ(expected_output.size(), total_len); + + auto* actual = output_tensor->GetTensorMutableData(); + for (size_t i = 0; i != total_len; ++i) { + if constexpr (std::is_same::value || std::is_same::value) { + EXPECT_NEAR(expected_output[i], actual[i], 1e-3) << "i=" << i; + } else { + EXPECT_EQ(expected_output[i], actual[i]) << "i=" << i; + } + } +} diff --git a/onnxruntime/test/testdata/attention/attention_test_data.txt b/onnxruntime/test/testdata/attention/attention_test_data.txt index 7c60efea1f0f6..49f4a6d4f7396 100644 --- a/onnxruntime/test/testdata/attention/attention_test_data.txt +++ b/onnxruntime/test/testdata/attention/attention_test_data.txt @@ -5066,3 +5066,901 @@ name:CrossAttention_Batch1_HeadSize8_NoBias.output -0.15928616,-0.13984840,0.07850466,0.10540886,1.54793286,0.43936923,0.40107274,-1.26946867, 0.86807090,0.27874026,0.24483341,1.36524665,1.07833946,-0.42526853,0.03085684,-1.09703445 + +==== +name:SelfAttention_PastPresentBufferShare_UsingDMMHAInsideMHA.query_data +1.7640524,0.4001572,0.978738,2.2408931,1.867558,-0.9772779,0.95008844,-0.1513572, +-0.10321885,0.41059852,0.14404356,1.4542735,0.7610377,0.121675014,0.44386324,0.33367434, +1.4940791,-0.20515826,0.3130677,-0.85409576,-2.5529897,0.6536186,0.8644362,-0.742165, +2.2697546,-1.4543657,0.045758516,-0.18718386,1.5327792,1.4693588,0.15494743,0.37816253, +-0.88778573,-1.9807965,-0.34791216,0.15634897,1.2302907,1.2023798,-0.3873268,-0.30230275, +-1.048553,-1.420018,-1.7062702,1.9507754,-0.5096522,-0.4380743,-1.2527953,0.7774904, +-1.6138978,-0.21274029,-0.89546657,0.3869025,-0.51080513,-1.1806322,-0.028182229,0.42833188, +0.06651722,0.3024719,-0.6343221,-0.36274117,-0.67246044,-0.35955316,-0.8131463,-1.7262826, +0.17742614,-0.40178093,-1.6301984,0.46278226,-0.9072984,0.051945396,0.7290906,0.12898292, +1.1394007,-1.2348258,0.40234163,-0.6848101,-0.87079716,-0.5788497,-0.31155252,0.05616534, +-1.1651498,0.9008265,0.46566245,-1.5362437,1.4882522,1.8958892,1.1787796,-0.17992483, +-1.0707526,1.0544517,-0.40317693,1.222445,0.20827498,0.97663903,0.3563664,0.7065732, +0.01050002,1.7858706,0.12691209,0.40198937,1.8831507,-1.347759,-1.270485,0.9693967, +-1.1731234,1.9436212,-0.41361898,-0.7474548,1.922942,1.4805148,1.867559,0.90604466, +-0.86122566,1.9100649,-0.26800337,0.8024564,0.947252,-0.15501009,0.61407936,0.9222067, +0.37642553,-1.0994008,0.2982382,1.3263859,-0.69456786,-0.14963454,-0.43515354,1.8492638 + +==== +name:SelfAttention_PastPresentBufferShare_UsingDMMHAInsideMHA.key_data +0.67229474,0.40746182,-0.76991606,0.5392492,-0.6743327,0.031830557,-0.6358461,0.67643327, +0.57659084,-0.20829876,0.3960067,-1.0930616,-1.4912575,0.4393917,0.1666735,0.63503146, +2.3831449,0.94447947,-0.91282225,1.1170163,-1.3159074,-0.4615846,-0.0682416,1.7133427, +-0.74475485,-0.82643855,-0.09845252,-0.6634783,1.1266359,-1.0799315,-1.1474687,-0.43782005, +-0.49803245,1.929532,0.9494208,0.08755124,-1.2254355,0.844363,-1.0002153,-1.5447711, +1.1880298,0.3169426,0.9208588,0.31872764,0.8568306,-0.6510256,-1.0342429,0.6815945, +-0.80340964,-0.6895498,-0.4555325,0.017479159,-0.35399392,-1.3749512,-0.6436184,-2.2234032, +0.62523144,-1.6020577,-1.1043833,0.05216508,-0.739563,1.5430146,-1.2928569,0.26705086, +-0.039282817,-1.1680934,0.5232767,-0.17154633,0.77179056,0.82350415,2.163236,1.336528, +-0.36918184,-0.23937918,1.0996596,0.6552637,0.64013153,-1.616956,-0.024326125,-0.7380309, +0.2799246,-0.09815039,0.9101789,0.3172182,0.78632796,-0.4664191,-0.94444627,-0.4100497, +-0.017020414,0.37915173,2.259309,-0.042257152,-0.955945,-0.34598178,-0.463596,0.48148146, +-1.540797,0.06326199,0.15650654,0.23218104,-0.5973161,-0.23792173,-1.424061,-0.49331987, +-0.54286146,0.41605005,-1.1561824,0.7811981,1.4944845,-2.069985,0.42625874,0.676908, +-0.63743705,-0.3972718,-0.13288058,-0.29779088,-0.30901298,-1.6760038,1.1523316,1.0796186, +-0.81336427,-1.4664243,0.5210649,-0.57578796,0.14195317,-0.31932843,0.69153875,0.6947491 + +==== +name:SelfAttention_PastPresentBufferShare_UsingDMMHAInsideMHA.value_data +-0.7255974,-1.383364,-1.5829384,0.6103794,-1.1888592,-0.5068163,-0.596314,-0.052567296, +-1.9362798,0.1887786,0.52389103,0.08842209,-0.31088617,0.097400166,0.39904633,-2.7725928, +1.9559124,0.39009333,-0.6524086,-0.39095336,0.49374178,-0.11610394,-2.0306845,2.064493, +-0.11054066,1.0201727,-0.69204986,1.5363771,0.2863437,0.60884386,-1.0452534,1.2111453, +0.68981814,1.3018463,-0.6280876,-0.48102713,2.3039167,-1.0600158,-0.1359497,1.1368914, +0.09772497,0.5829537,-0.39944902,0.37005588,-1.3065269,1.6581306,-0.11816405,-0.6801782, +0.6663831,-0.4607198,-1.3342584,-1.3467175,0.69377315,-0.15957344,-0.13370156,1.0777438, +-1.1268258,-0.7306777,-0.3848798,0.09435159,-0.042171452,-0.2868872,-0.0616264,-0.10730527, +-0.7196044,-0.812993,0.27451634,-0.8909151,-1.1573553,-0.31229225,-0.15766701,2.2567234, +-0.7047003,0.9432607,0.7471883,-1.1889449,0.77325296,-1.1838807,-2.6591723,0.60631955, +-1.7558906,0.45093447,-0.6840109,1.6595508,1.0685093,-0.4533858,-0.6878376,-1.2140774, +-0.44092262,-0.28035548,-0.36469355,0.15670386,0.5785215,0.34965447,-0.76414394,-1.4377915, +1.3645319,-0.6894492,-0.6522936,-0.52118933,-1.8430696,-0.477974,-0.4796558,0.6203583, +0.6984571,0.003770889,0.93184835,0.339965,-0.015682112,0.16092817,-0.19065349,-0.3948495, +-0.26773354,-1.1280113,0.2804417,-0.9931236,0.8416313,-0.24945858,0.04949498,0.4938368, +0.6433145,-1.5706234,-0.20690368,0.8801789,-1.6981058,0.38728046,-2.2555642,-1.0225068 + +==== +name:SelfAttention_PastPresentBufferShare_UsingDMMHAInsideMHA.bias_data +0.038630553,-1.6567152,-0.98551077,-1.471835,1.648135,0.16422775,0.5672903,-0.2226751, +-0.35343176,-1.6164742,-0.29183736,-0.7614922,0.8579239,1.1411018,1.4665787,0.85255194, +-0.5986539,-1.1158969,0.7666632,0.3562928,-1.7685385,0.3554818,0.8145198,0.058925588, +-0.18505368,-0.8076485,-1.4465348,0.800298,-0.30911446,-0.23346666,1.7327212,0.6845011, +0.370825,0.1420618,1.5199949,1.7195894,0.9295051,0.5822246,-2.094603,0.12372191, +-0.13010696,0.09395323,0.9430461,-2.7396772,-0.56931204,0.26990435,-0.46684554,-1.4169061, +0.8689635,0.27687192,-0.97110456,0.3148172,0.8215857,0.005292646,0.8005648,0.078260176, +-0.39522898,-1.1594205,-0.085930765,0.19429293,0.87583274,-0.11510747,0.4574156,-0.964612, +-0.78262913,-0.1103893,-1.0546285,0.8202478,0.46313033,0.27909577,0.3389041,2.0210435, +-0.4688642,-2.2014413,0.1993002,-0.050603542,-0.51751906,-0.97882986,-0.43918952,0.18133843, +-0.5028167,2.4124537,-0.96050435,-0.79311734,-2.28862,0.25148442,-2.0164065,-0.53945464, +-0.27567053,-0.70972794,1.7388726,0.99439436,1.3191369,-0.8824188,1.128594,0.49600095, +0.77140594,1.0294389,-0.90876323,-0.42431763,0.86259604,-2.6556191,1.5133281,0.55313206, +-0.045703962,0.22050765,-1.0299352,-0.34994337,1.1002843,1.298022,2.696224,-0.07392467, +-0.65855294,-0.51423395,-1.0180418,-0.07785475,0.38273242,-0.03424228,1.0963469,-0.2342158, +-0.34745064,-0.5812685,-1.6326345,-1.5677677,-1.179158,1.3014281,0.8952603,1.3749641, +-1.3322116,-1.9686247,-0.6600563,0.17581895,0.49869028,1.0479722,0.28427967,1.7426687, +-0.22260568,-0.9130792,-1.6812183,-0.8889713,0.24211796,-0.8887203,0.9367425,1.4123276, +-2.369587,0.8640523,-2.239604,0.40149906,1.2248706,0.064856105,-1.2796892,-0.5854312, +-0.26164544,-0.18224478,-0.20289683,-0.10988278,0.21348006,-1.2085737,-0.24201983,1.5182612, +-0.38464543,-0.4438361,1.0781974,-2.5591846,1.1813786,-0.63190377,0.16392857,0.09632136, +0.9424681,-0.26759475,-0.6780258,1.2978458,-2.364174,0.020334182,-1.3479254,-0.7615734, +2.0112567,-0.044595428,0.1950697,-1.7815628,-0.7290447,0.1965574,0.3547577,0.61688656, +0.008627899,0.5270042,0.4537819,-1.8297404,0.037005723,0.76790243,0.5898798,-0.36385882 + +==== +name:SelfAttention_PastPresentBufferShare_UsingDMMHAInsideMHA.past_key_data +-0.8056265,-1.1183119,-0.13105401,1.1330799,-1.9518042,-0.6598917,-1.1398025,0.7849575, +-0.5543096,-0.47063765,-0.21694957,0.44539326,-0.392389,-3.046143,0.5433119,0.43904296, +-0.21954103,-1.0840366,0.35178012,0.37923554,-0.47003287,-0.21673147,-0.9301565,-0.17858909, +-1.5504293,0.41731882,-0.9443685,0.23810315,-1.405963,-0.5900577,-0.110489406,-1.6606998, +0.115147874,-0.37914756,-1.7423562,-1.3032428,0.60512006,0.895556,-0.13190864,0.40476182, +0.22384356,0.32962298,1.285984,-1.5069984,0.67646074,-0.38200897,-0.22425893,-0.30224973, +-0.3751471,-1.2261962,0.1833392,1.670943,-0.05613302,-0.0013850428,-0.687299,-0.11747455, +0.46616644,-0.37024245,-0.45380405,0.40326455,-0.91800475,0.25249663,0.8203218,1.3599485, +-0.09038201,1.3675972,1.0344099,-0.99621266,-1.2179385,-0.30496365,1.0289356,-0.07228701, +-0.6006576,1.5522432,0.28690448,-2.3205943,0.31716064,0.52004063,0.22560866,0.4497121, +-0.067275606,-1.3183959,-0.370704,-0.94561577,-0.9327409,-1.2630683,0.45248908,0.097896144, +-0.44816536,-0.64933795,-0.023423105,1.0791948,-2.0042157,0.37687653,-0.545712,-1.8845859, +-1.945703,-0.9127835,0.21950956,0.39306292,-0.9389816,1.017021,1.4229835,0.39608657, +-0.59140265,1.1244192,0.7553957,0.86740744,-0.6564637,-2.8345544,2.116791,-1.6108783, +-0.035768073,2.3807454,0.33057675,0.94924647,-1.5023966,-1.7776669,-0.5327028,1.0907497, +-0.34624946,-0.7946363,0.19796729,1.0819352,-1.4449402,-1.210543,-0.7886692,1.0946383, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.23482153,2.1321535,0.9364457,-0.035095178,1.2650778,0.21149701,-0.70492136,0.67997485, +-0.6963267,-0.2903971,1.3277828,-0.10128149,-0.8031414,-0.46433768,1.0217906,-0.55254066, +-0.38687086,-0.51029277,0.1839255,-0.38548976,-1.6018361,-0.8871809,-0.932789,1.2433194, +0.81267405,0.58725935,-0.50535834,-0.81579155,-0.5075176,-1.0518801,2.4972005,-2.2453218, +0.56400853,-1.2845523,-0.10434349,-0.98800194,-1.177629,-1.1401963,1.7549862,-0.13298842, +-0.7657022,0.55578697,0.010349315,0.72003376,-1.8242567,0.30360392,0.7726948,-1.6615983, +0.44819528,1.6961815,-0.014857704,0.82140595,0.67057043,-0.7075057,0.039766736,-1.5669947, +-0.45130304,0.26568797,0.7231005,0.024612125,0.71998376,-1.1029062,-0.10169727,0.019279385, +1.8495913,-0.21416666,-0.49901664,0.021351224,-0.91911346,0.19275385,-0.3650552,-1.7913276, +-0.058586553,-0.3175431,-1.6324233,-0.06713416,1.4893559,0.5213038,0.6119272,-1.3414967, +0.47689837,0.14844958,0.5290452,0.4226286,-1.3597807,-0.041400813,-0.75787085,-0.050084095, +-0.8974009,1.3124703,-0.8589724,-0.8989422,0.07458641,-1.0770991,-0.4246633,-0.8299646, +1.411172,0.78580385,-0.057469517,-0.39121705,0.9409176,0.4052041,0.49805242,-0.026192237, +-1.68823,-0.112465985,-0.5324899,0.6450553,1.0118425,-0.65795106,0.46838522,1.735879, +-0.66771275,1.6819217,-0.85258585,0.022959756,-0.011145612,0.0114989,-0.837678,-0.5911831, +-0.66772026,0.3269626,0.33003512,2.2259443,1.370989,-0.50984323,0.3248696,0.997118, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.030601824,-0.069641575,0.05157494,0.8672766,-0.84832054,-0.32566947,0.47043315,0.31144708, +0.23958276,-0.36980116,0.9725358,2.1338682,0.4064155,-0.1931767,0.7557403,-0.53913265, +-0.74969035,0.032808747,-2.5827966,-1.1539503,-0.34796184,-1.3533889,-1.0326431,-0.43674833, +-1.6429653,-0.40607178,-0.53527015,0.025405208,1.154184,0.17250441,0.021062022,0.099454455, +0.22739278,-1.0167387,-0.11477532,0.30875126,-1.37076,0.8656529,1.0813761,-0.63137597, +-0.24133779,-0.87819034,0.69938046,-1.0612223,-0.222477,-0.8589199,0.05095428,-1.7942293, +1.3264617,-0.9646064,0.059894685,-0.21252304,-0.7621145,-0.88778013,0.93639857,-0.5256406, +0.2711702,-0.80149686,-0.64718145,0.47224715,0.9304085,-0.17531641,-1.4219198,1.997956, +-0.8565493,-1.5415874,2.5944245,-0.4040323,-1.4617327,-0.6834398,0.3675449,0.19031155, +-0.8517292,1.8227236,-0.5215797,-1.1846865,0.9606934,1.3290628,-0.8174931,-1.4013473, +1.0304383,-2.0473237,-1.2266216,0.96744615,-0.055352546,-0.26393735,0.3528166,-0.15277442, +-1.2986867,1.2760754,1.325014,0.20533256,0.045134015,2.339625,-0.27643284,-0.25957698, +0.36448124,1.471322,1.5927707,-0.25857264,0.30833125,-1.3780835,-0.3119761,-0.84029037, +-1.0068318,1.6815767,-0.79228663,-0.5316059,0.36584878,1.2978252,0.48111513,2.759355, +-0.074667975,0.25871643,0.27560067,1.4350494,0.5072389,-0.1162297,-0.9474886,0.24444346, +1.4013448,-0.4103818,0.5289436,0.24614778,0.86351967,-0.8047537,2.346647,-1.2791611, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +-0.36555108,0.9380925,0.29673317,0.82998616,-0.49610233,-0.074804984,0.012231983,1.5692596, +0.69042903,0.7966721,-0.6579261,0.9688826,0.22558166,1.3891454,2.0140603,-0.30676576, +-0.40630314,-0.86404496,-0.14357951,-0.38202545,0.3595044,-0.14456682,-0.36159927,1.0645851, +-0.9378802,0.43310794,-0.40594172,0.7243685,1.3852615,-0.30309826,0.44103292,0.17879286, +-0.7994224,0.2407875,0.2891205,0.41287082,-0.1983989,0.0941923,-1.1476109,-0.35811406, +0.5559627,0.8924739,-0.42231482,0.10471403,0.22805333,0.20147994,0.5407736,-1.8180777, +-0.04932407,0.2390336,-1.0003303,1.6739857,0.16155927,1.5634048,-0.790523,-0.9073001, +0.22425222,-1.6786884,0.2149656,0.09721923,1.0156653,0.70104134,-0.41747734,-1.0974966, +1.7123052,-0.79211503,-1.0455246,-1.084856,1.1173053,-0.5189002,-0.7537045,0.13768983, +-0.2069447,-0.67809546,0.7539915,1.0653155,0.9853175,0.7669197,0.40262553,-1.775888, +1.6692508,0.3019892,0.60815644,1.1149623,1.4333525,0.41839802,0.43554616,-0.59922427, +0.03308975,-0.85416126,-0.71994054,-0.8935744,-0.15602389,1.0490932,3.1709747,0.18949963, +-1.3484131,1.2649833,-0.30078387,-0.6606086,0.20984948,-1.2406245,0.22246316,-0.08837552, +0.098377906,0.38141626,0.067492254,0.016338084,0.2843145,0.41540062,-1.0314825,-1.4299912, +-0.061638054,-1.4327354,0.08753147,0.93874687,0.6071117,-1.0481704,-0.86026245,0.32830128, +-0.4012978,-0.3166553,0.5969065,-0.9872867,-0.40123472,-0.8000825,-1.0431294,-0.8570782, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 + +==== +name:SelfAttention_PastPresentBufferShare_UsingDMMHAInsideMHA.past_value_data +0.67746216,0.05182039,-0.87916064,-0.2311016,-1.6388073,-0.7333128,2.1495745,-0.090243846, +0.73165894,-0.065488376,0.34816924,0.6632581,-1.1046166,-0.030936258,1.5788652,-0.7955006, +-0.56643987,-0.30769128,0.26902407,0.52491784,1.2674117,0.49949825,-0.062053125,1.2591671, +0.70411104,-1.4956795,2.5263681,1.7699214,-0.16821422,0.3779101,1.3243587,-0.1722008, +0.7303518,1.1045785,-1.0148259,-0.6023319,0.9214084,0.46081448,0.92379653,-0.13256802, +-0.28900522,-1.9986395,-1.1460004,0.047066096,0.82455724,0.53117836,-0.12824197,-0.27177158, +0.21717963,0.07821118,1.4045455,0.14644077,-1.481246,-1.2725581,1.5187594,-1.1711605, +0.76449746,-0.26837274,-0.16975829,-0.13413279,1.221385,-0.19284183,-0.033319283,-1.5308034, +0.2066905,0.5310425,0.23914558,1.3978963,0.055171356,0.29897746,1.648504,-1.5500141, +-0.45582536,1.4261588,0.93612915,0.6783801,0.8326507,0.3270662,1.6315974,0.37775916, +0.2398671,0.15895867,0.19286396,-1.1570172,0.77067304,-0.13043973,1.8219151,-0.07565047, +0.4209183,0.24660219,-0.625557,0.99213684,1.9050636,-0.01477722,-0.3004788,-0.35502872, +-1.8923619,-0.17781314,0.2509981,1.054758,0.9600477,-0.41649908,-0.27682298,1.1239053, +-0.1734639,-0.51002955,1.3925184,1.0375856,0.018791791,-0.5937774,-2.0118804,0.5897036, +-0.8963697,-1.962732,1.5848205,0.6479678,-1.1390082,-1.2144014,0.8709618,-0.87797064, +1.2961498,0.6164593,0.53659654,0.40469545,0.19145088,0.8805112,-0.45408037,0.08595198, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.75194657,0.5629897,-1.1949868,-0.50040966,0.2528035,-0.4080147,1.7746586,-0.3931532, +-0.16221845,0.76943016,0.33053273,-0.14527446,-0.7564935,0.30151406,1.0390965,0.47909522, +-0.7781835,1.7367749,-1.4465779,-1.5826856,0.9605572,0.22584048,-0.54949856,-1.0985707, +2.3207998,0.11709087,0.53420115,0.3178851,0.43480796,0.54009444,0.732424,-0.3752224, +-0.29164198,-1.7410228,-0.78030443,0.2711128,1.0450233,0.59903955,-0.34069234,-1.2631729, +-2.7773592,1.151734,-0.589229,-0.44846502,0.13157398,-1.40556,-0.34978217,2.0234718, +0.50538695,0.35924914,-1.5824945,2.2436018,-1.4227949,1.9223248,-2.115056,1.4053655, +1.6180543,-0.8244091,0.42258036,0.5474806,-0.8137945,-1.4491177,-1.3177173,0.54100823, +-0.085115604,-0.564301,0.966768,0.5080679,-0.7554627,-1.2012016,0.5232617,-0.53758335, +0.09920486,1.576299,0.5023282,-0.862267,0.16066119,-0.95264494,1.6085222,-0.56157875, +0.20727074,0.30773258,0.15925047,-1.9585489,-1.446421,-0.4523503,0.31943184,-0.13777922, +-0.9571475,-1.3484243,-0.40155753,-0.46847606,0.51283646,-0.32631847,0.6027077,-0.5946498, +-0.25595766,-0.3480464,-0.782367,0.6251187,-0.813596,-0.5216415,-0.07311965,-1.2973796, +-0.32493496,-0.71130633,-0.38815418,-0.059928004,-0.79991364,-0.22007579,1.3086687,-0.025798557, +1.1452621,0.34649444,0.7741606,-0.77445894,0.10490716,0.13391292,-0.6126257,-0.82282835, +-1.4902654,1.4961396,-0.9724029,1.3462211,-0.46749318,-0.8624933,0.62251914,-0.63119197, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.5684589,-0.33281177,0.4804245,-0.9681861,0.83135104,0.48797268,-0.9196507,2.6429358, +0.54012305,2.290467,1.6002678,-0.18883479,-0.41227177,-0.4034592,-1.8300285,-0.6958351, +0.24676603,1.5259576,-0.7727719,0.8820566,-1.2525934,-0.58632004,-0.4576406,0.3718111, +0.45730963,0.9623417,0.77083695,0.24316822,0.39036494,1.5885307,-0.5109262,0.7747283, +-1.808144,0.41133425,-0.48324955,0.0025711823,1.0400863,0.16464381,0.88518757,1.4737648, +0.38909397,1.171041,-0.32656097,-0.008209882,-0.5226194,1.0429776,0.41409135,-0.50723445, +0.15466884,1.0415684,-0.03926799,-0.9489328,0.13191175,-1.9805655,0.76877064,-0.4213276, +-0.46931073,0.8756957,-1.3651628,1.9470986,-0.48024204,-0.52325094,1.0212247,0.7086953, +2.4512298,-0.21120599,-0.120406635,-1.479316,-0.33210227,-0.7214313,-0.448767,-1.7441877, +1.6606076,-1.4166034,-2.8022027,-1.1884245,-0.6038396,-1.149554,1.0983036,-0.13783918, +0.025385605,0.61039174,0.28601253,0.9785673,-1.1094775,-0.5475181,0.66596717,-2.5345545, +-1.3751845,0.50099224,-0.48024905,0.9361076,0.8091803,-1.1980929,0.4066571,1.2016978, +0.1474344,-0.97746485,0.87938994,0.63542455,0.54261076,0.71593887,-2.994613,0.8809376, +1.8081318,0.43663847,0.192729,0.69643867,0.33822548,0.65178126,0.0014710003,-0.76670486, +-1.0043228,-0.9981917,-1.3730426,-1.067742,1.7612661,0.7540957,-0.6250274,-0.3903927, +0.11255753,-0.65554506,0.067516856,0.77760416,-0.035742734,0.33601573,0.88649154,-0.27213177, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.2847906,-0.30937758,-0.02852887,-0.32473028,-0.52886987,0.17371185,0.5665453,0.14630444, +0.49872696,-0.7379318,-1.2037352,0.4170435,0.6878814,0.049857266,1.3480358,0.9076988, +2.6805708,-0.20080851,-0.9988488,-0.7401368,-0.5654978,0.4760314,-2.1580687,1.3185511, +-0.23929659,-0.24679355,-1.0793432,-0.11422555,0.013239767,-0.12194493,0.33905926,-0.58963203, +-0.8958158,0.5483281,0.09866745,0.19718106,1.0590272,-1.0225644,-0.85524046,1.2572197, +-1.4828833,-1.3094121,0.81786186,0.23820019,0.105232134,-0.09165941,0.031267546,-0.09211212, +1.3554426,-0.39814812,-0.16137354,1.7944489,0.027509702,2.2320163,-0.1049797,1.367415, +-1.655344,0.15364446,-1.5844736,0.8444543,-1.2128679,0.28376955,-0.28219587,-1.1582032, +-1.61936,-0.51104045,1.7406294,-0.29348505,0.91722155,-0.057042867,0.87672675,-1.8269113, +-0.40318832,0.94940555,-0.16325495,-0.086455286,-0.4304619,1.1493794,0.29751435,0.044022277, +0.64305454,0.58822495,0.21258704,1.5470315,-0.060287535,0.27808106,-0.64295256,0.15011522, +1.5877615,-0.6432576,-1.1335928,0.99675965,-0.14876615,0.0960042,-0.045113303,0.079121724, +0.8505307,-0.8391242,-1.0117741,0.084968135,-1.6064397,-1.3730536,1.8666831,0.75746834, +-0.010056471,1.238007,-1.0405992,-0.31560314,0.6234536,0.8906717,0.51291686,-2.5412388, +-0.96808213,0.4770681,-0.3559515,2.5402317,0.9265583,0.55808187,-1.1169496,-0.03529674, +0.24120396,1.1277837,0.8811311,1.0329891,-0.923912,1.4121517,-1.3804307,-0.53591454, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 + +==== +name:SelfAttention_PastPresentBufferShare_UsingDMMHAInsideMHA.fp32_output_data +-1.4901291,-0.6127523,-0.37208983,0.81460416,0.49231845,-0.15108852,0.013023794,0.95520675, +-0.5171256,-0.5793653,0.6358129,0.5813584,0.05082538,-0.4695547,-0.9157753,0.08151066, +-0.6503749,-1.0304339,0.6261372,0.40946347,-0.45083562,-0.8799362,0.14981574,-0.33481675, +0.8797696,0.4651931,0.26085043,0.63520896,0.38815358,0.455564,-0.48009312,0.40361634, +0.16237563,-0.20201929,-0.098145366,0.116463386,-0.25710258,-0.7530771,0.79561776,-0.60588866, +-0.18908973,0.94241863,0.2322133,-0.44546735,-0.34606236,-0.41458836,1.2162775,-0.015568115, +0.074197866,0.77310014,-0.40284765,-1.4562985,-0.4079464,-0.006341338,-0.23461592,-0.43371344, +0.18838094,-0.41541746,-0.11950366,0.080281585,0.26667595,-0.16386892,0.54090405,-0.46252388, +-0.74845964,-0.6411486,-0.11178234,-0.49679786,0.43254298,0.31444955,-0.09452905,1.9511061, +0.34721223,0.8587256,-0.23741366,-0.59594387,-0.09987013,-0.2511883,-0.54922277,0.04424855, +-0.88538414,1.0397384,-0.9184096,0.3502718,0.2802844,-0.9707793,-0.23891075,-0.7650979, +-0.362343,0.4538829,-0.50438243,0.9400783,0.1720767,-0.122763455,0.1329056,0.5681431, +0.56380415,-0.7173072,-0.26292765,-1.009201,-0.8017437,-1.1684775,0.6606952,0.7407442, +0.3417585,0.29830286,-0.29903686,0.4605967,-0.51642084,0.49119917,-0.25728413,-1.5713134, +0.42070937,-0.23215376,-0.03731747,0.5079436,0.45979655,0.5862025,-0.44871226,0.59794164, +0.12756062,0.16322222,0.20992519,0.29804617,-1.1845424,1.0947874,-1.2509774,-0.9073155 + +==== +name:SelfAttention_PastPresentBufferShare_UsingDMMHAInsideMHA.present_key_data +-0.8056265,-1.1183119,-0.13105401,1.1330799,-1.9518042,-0.6598917,-1.1398025,0.7849575, +-0.5543096,-0.47063765,-0.21694957,0.44539326,-0.392389,-3.046143,0.5433119,0.43904296, +-0.1103344,0.29707253,-1.8245445,1.3594971,-0.47003287,-0.21673147,-0.9301565,-0.17858909, +-1.5504293,0.41731882,-0.9443685,0.23810315,-1.405963,-0.5900577,-0.110489406,-1.6606998, +0.115147874,-0.37914756,-1.7423562,-1.3032428,0.60512006,0.895556,-0.13190864,0.40476182, +-0.21120235,0.31092632,-0.29694197,2.6974769,0.67646074,-0.38200897,-0.22425893,-0.30224973, +-0.3751471,-1.2261962,0.1833392,1.670943,-0.05613302,-0.0013850428,-0.687299,-0.11747455, +0.46616644,-0.37024245,-0.45380405,0.40326455,-0.91800475,0.25249663,0.8203218,1.3599485, +0.10772663,-2.40974,0.5953069,-1.1436651,-1.2179385,-0.30496365,1.0289356,-0.07228701, +-0.6006576,1.5522432,0.28690448,-2.3205943,0.31716064,0.52004063,0.22560866,0.4497121, +-0.067275606,-1.3183959,-0.370704,-0.94561577,-0.9327409,-1.2630683,0.45248908,0.097896144, +-2.0087767,-0.5394381,-0.272516,0.8163699,-2.0042157,0.37687653,-0.545712,-1.8845859, +-1.945703,-0.9127835,0.21950956,0.39306292,-0.9389816,1.017021,1.4229835,0.39608657, +-0.59140265,1.1244192,0.7553957,0.86740744,-0.6564637,-2.8345544,2.116791,-1.6108783, +1.8803282,3.356933,-1.8733265,0.32389897,-1.5023966,-1.7776669,-0.5327028,1.0907497, +-0.34624946,-0.7946363,0.19796729,1.0819352,-1.4449402,-1.210543,-0.7886692,1.0946383, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +-3.6045275,-0.21010017,-2.0846481,1.173888,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +-1.0204253,-1.5361664,1.6404201,0.33091605,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +2.4457726,-1.9623504,-0.018874645,0.0581809,0.0,0.0,0.0,0.0, +0.23482153,2.1321535,0.9364457,-0.035095178,1.2650778,0.21149701,-0.70492136,0.67997485, +-0.6963267,-0.2903971,1.3277828,-0.10128149,-0.8031414,-0.46433768,1.0217906,-0.55254066, +0.27337348,2.958971,0.04065758,-0.3367664,-1.6018361,-0.8871809,-0.932789,1.2433194, +0.81267405,0.58725935,-0.50535834,-0.81579155,-0.5075176,-1.0518801,2.4972005,-2.2453218, +0.56400853,-1.2845523,-0.10434349,-0.98800194,-1.177629,-1.1401963,1.7549862,-0.13298842, +-0.36283946,-1.8112562,0.5131128,-0.991639,-1.8242567,0.30360392,0.7726948,-1.6615983, +0.44819528,1.6961815,-0.014857704,0.82140595,0.67057043,-0.7075057,0.039766736,-1.5669947, +-0.45130304,0.26568797,0.7231005,0.024612125,0.71998376,-1.1029062,-0.10169727,0.019279385, +1.1423258,0.53745025,-0.10907644,-0.031215727,-0.91911346,0.19275385,-0.3650552,-1.7913276, +-0.058586553,-0.3175431,-1.6324233,-0.06713416,1.4893559,0.5213038,0.6119272,-1.3414967, +0.47689837,0.14844958,0.5290452,0.4226286,-1.3597807,-0.041400813,-0.75787085,-0.050084095, +1.9571149,0.64699644,1.6619811,0.60766983,0.07458641,-1.0770991,-0.4246633,-0.8299646, +1.411172,0.78580385,-0.057469517,-0.39121705,0.9409176,0.4052041,0.49805242,-0.026192237, +-1.68823,-0.112465985,-0.5324899,0.6450553,1.0118425,-0.65795106,0.46838522,1.735879, +-1.4619626,-1.2037838,-1.4735744,-0.060375594,-0.011145612,0.0114989,-0.837678,-0.5911831, +-0.66772026,0.3269626,0.33003512,2.2259443,1.370989,-0.50984323,0.3248696,0.997118, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.028738499,-1.4091935,0.45272845,-2.457619,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.2777808,-2.1833262,-2.7370179,-1.5156027,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +-1.918721,2.8444428,-0.39759666,1.642015,0.0,0.0,0.0,0.0, +0.030601824,-0.069641575,0.05157494,0.8672766,-0.84832054,-0.32566947,0.47043315,0.31144708, +0.23958276,-0.36980116,0.9725358,2.1338682,0.4064155,-0.1931767,0.7557403,-0.53913265, +-0.82191193,-1.2784828,-0.5313518,0.6487015,-0.34796184,-1.3533889,-1.0326431,-0.43674833, +-1.6429653,-0.40607178,-0.53527015,0.025405208,1.154184,0.17250441,0.021062022,0.099454455, +0.22739278,-1.0167387,-0.11477532,0.30875126,-1.37076,0.8656529,1.0813761,-0.63137597, +1.2349209,1.1025999,2.50214,3.3575716,-0.222477,-0.8589199,0.05095428,-1.7942293, +1.3264617,-0.9646064,0.059894685,-0.21252304,-0.7621145,-0.88778013,0.93639857,-0.5256406, +0.2711702,-0.80149686,-0.64718145,0.47224715,0.9304085,-0.17531641,-1.4219198,1.997956, +-0.8380461,-2.4408205,1.2989597,0.60466015,-1.4617327,-0.6834398,0.3675449,0.19031155, +-0.8517292,1.8227236,-0.5215797,-1.1846865,0.9606934,1.3290628,-0.8174931,-1.4013473, +1.0304383,-2.0473237,-1.2266216,0.96744615,-0.055352546,-0.26393735,0.3528166,-0.15277442, +0.12261248,-2.5957859,-0.46351564,-0.5566925,0.045134015,2.339625,-0.27643284,-0.25957698, +0.36448124,1.471322,1.5927707,-0.25857264,0.30833125,-1.3780835,-0.3119761,-0.84029037, +-1.0068318,1.6815767,-0.79228663,-0.5316059,0.36584878,1.2978252,0.48111513,2.759355, +-0.22289208,2.3143032,-0.050325453,-0.47589913,0.5072389,-0.1162297,-0.9474886,0.24444346, +1.4013448,-0.4103818,0.5289436,0.24614778,0.86351967,-0.8047537,2.346647,-1.2791611, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +-1.502292,-0.21493468,-2.9608529,-0.9495044,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +-0.29269093,-0.3305762,3.9981818,0.95213723,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.36319184,-1.2284006,0.66499805,0.97748244,0.0,0.0,0.0,0.0, +-0.36555108,0.9380925,0.29673317,0.82998616,-0.49610233,-0.074804984,0.012231983,1.5692596, +0.69042903,0.7966721,-0.6579261,0.9688826,0.22558166,1.3891454,2.0140603,-0.30676576, +-0.76939106,1.0927008,-0.7522567,-0.19213659,0.3595044,-0.14456682,-0.36159927,1.0645851, +-0.9378802,0.43310794,-0.40594172,0.7243685,1.3852615,-0.30309826,0.44103292,0.17879286, +-0.7994224,0.2407875,0.2891205,0.41287082,-0.1983989,0.0941923,-1.1476109,-0.35811406, +0.26527995,-2.8935409,0.089267135,0.05981219,0.22805333,0.20147994,0.5407736,-1.8180777, +-0.04932407,0.2390336,-1.0003303,1.6739857,0.16155927,1.5634048,-0.790523,-0.9073001, +0.22425222,-1.6786884,0.2149656,0.09721923,1.0156653,0.70104134,-0.41747734,-1.0974966, +-0.5885654,0.6365577,-2.1861176,0.4312547,1.1173053,-0.5189002,-0.7537045,0.13768983, +-0.2069447,-0.67809546,0.7539915,1.0653155,0.9853175,0.7669197,0.40262553,-1.775888, +1.6692508,0.3019892,0.60815644,1.1149623,1.4333525,0.41839802,0.43554616,-0.59922427, +2.594769,-0.7719629,3.1224828,0.60298336,-0.15602389,1.0490932,3.1709747,0.18949963, +-1.3484131,1.2649833,-0.30078387,-0.6606086,0.20984948,-1.2406245,0.22246316,-0.08837552, +0.098377906,0.38141626,0.067492254,0.016338084,0.2843145,0.41540062,-1.0314825,-1.4299912, +-1.29599,-0.91150576,-1.1509224,-0.37564564,0.6071117,-1.0481704,-0.86026245,0.32830128, +-0.4012978,-0.3166553,0.5969065,-0.9872867,-0.40123472,-0.8000825,-1.0431294,-0.8570782, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.07371944,-1.7102461,2.2486784,0.8454028,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +-1.1608149,-2.0476928,-1.1115696,-2.1435556,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +-1.0372047,0.98209965,1.586799,2.069713,0.0,0.0,0.0,0.0 + +==== +name:SelfAttention_PastPresentBufferShare_UsingDMMHAInsideMHA.present_value_data +0.67746216,0.05182039,-0.87916064,-0.2311016,-1.6388073,-0.7333128,2.1495745,-0.090243846, +0.73165894,-0.065488376,0.34816924,0.6632581,-1.1046166,-0.030936258,1.5788652,-0.7955006, +-0.56643987,-0.30769128,0.26902407,0.52491784,1.2674117,0.49949825,-0.062053125,1.2591671, +0.70411104,-1.4956795,2.5263681,1.7699214,-0.16821422,0.3779101,1.3243587,-0.1722008, +0.7303518,1.1045785,-1.0148259,-0.6023319,0.9214084,0.46081448,0.92379653,-0.13256802, +-0.28900522,-1.9986395,-1.1460004,0.047066096,0.82455724,0.53117836,-0.12824197,-0.27177158, +0.21717963,0.07821118,1.4045455,0.14644077,-1.481246,-1.2725581,1.5187594,-1.1711605, +0.76449746,-0.26837274,-0.16975829,-0.13413279,1.221385,-0.19284183,-0.033319283,-1.5308034, +0.2066905,0.5310425,0.23914558,1.3978963,0.055171356,0.29897746,1.648504,-1.5500141, +-0.45582536,1.4261588,0.93612915,0.6783801,0.8326507,0.3270662,1.6315974,0.37775916, +0.2398671,0.15895867,0.19286396,-1.1570172,0.77067304,-0.13043973,1.8219151,-0.07565047, +0.4209183,0.24660219,-0.625557,0.99213684,1.9050636,-0.01477722,-0.3004788,-0.35502872, +-1.8923619,-0.17781314,0.2509981,1.054758,0.9600477,-0.41649908,-0.27682298,1.1239053, +-0.1734639,-0.51002955,1.3925184,1.0375856,0.018791791,-0.5937774,-2.0118804,0.5897036, +-0.8963697,-1.962732,1.5848205,0.6479678,-1.1390082,-1.2144014,0.8709618,-0.87797064, +1.2961498,0.6164593,0.53659654,0.40469545,0.19145088,0.8805112,-0.45408037,0.08595198, +-2.0578089,-3.3519888,-2.2429948,0.7861984,-0.690169,0.5411559,-0.31203434,1.6901015, +-2.1588855,-0.7243006,-1.1573272,-0.80054927,-0.06876822,-0.7913201,1.3357888,-1.3602651, +-0.4136746,1.2541456,-2.8920126,0.010545701,1.7186123,-0.051247835,-3.3103738,1.4790617, +-0.3721861,0.83792794,-0.8949467,1.4264942,0.49982375,-0.59972984,-1.2872732,2.7294064, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.75194657,0.5629897,-1.1949868,-0.50040966,0.2528035,-0.4080147,1.7746586,-0.3931532, +-0.16221845,0.76943016,0.33053273,-0.14527446,-0.7564935,0.30151406,1.0390965,0.47909522, +-0.7781835,1.7367749,-1.4465779,-1.5826856,0.9605572,0.22584048,-0.54949856,-1.0985707, +2.3207998,0.11709087,0.53420115,0.3178851,0.43480796,0.54009444,0.732424,-0.3752224, +-0.29164198,-1.7410228,-0.78030443,0.2711128,1.0450233,0.59903955,-0.34069234,-1.2631729, +-2.7773592,1.151734,-0.589229,-0.44846502,0.13157398,-1.40556,-0.34978217,2.0234718, +0.50538695,0.35924914,-1.5824945,2.2436018,-1.4227949,1.9223248,-2.115056,1.4053655, +1.6180543,-0.8244091,0.42258036,0.5474806,-0.8137945,-1.4491177,-1.3177173,0.54100823, +-0.085115604,-0.564301,0.966768,0.5080679,-0.7554627,-1.2012016,0.5232617,-0.53758335, +0.09920486,1.576299,0.5023282,-0.862267,0.16066119,-0.95264494,1.6085222,-0.56157875, +0.20727074,0.30773258,0.15925047,-1.9585489,-1.446421,-0.4523503,0.31943184,-0.13777922, +-0.9571475,-1.3484243,-0.40155753,-0.46847606,0.51283646,-0.32631847,0.6027077,-0.5946498, +-0.25595766,-0.3480464,-0.782367,0.6251187,-0.813596,-0.5216415,-0.07311965,-1.2973796, +-0.32493496,-0.71130633,-0.38815418,-0.059928004,-0.79991364,-0.22007579,1.3086687,-0.025798557, +1.1452621,0.34649444,0.7741606,-0.77445894,0.10490716,0.13391292,-0.6126257,-0.82282835, +-1.4902654,1.4961396,-0.9724029,1.3462211,-0.46749318,-0.8624933,0.62251914,-0.63119197, +0.3051727,0.8580102,0.45010978,-3.0402117,3.4852953,-1.6919196,0.027978867,1.2332127, +1.0401931,0.31535894,-1.0774748,1.6679018,-3.6707008,1.6784648,-1.4660895,-1.4417516, +2.6776397,-0.50531524,-1.1391888,-3.1282802,-0.035271525,0.036983967,0.22105613,1.6946304, +-1.1181979,-0.20367354,0.068902105,-1.7353888,-0.0051657297,0.48101524,0.52825344,-0.4711641, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.5684589,-0.33281177,0.4804245,-0.9681861,0.83135104,0.48797268,-0.9196507,2.6429358, +0.54012305,2.290467,1.6002678,-0.18883479,-0.41227177,-0.4034592,-1.8300285,-0.6958351, +0.24676603,1.5259576,-0.7727719,0.8820566,-1.2525934,-0.58632004,-0.4576406,0.3718111, +0.45730963,0.9623417,0.77083695,0.24316822,0.39036494,1.5885307,-0.5109262,0.7747283, +-1.808144,0.41133425,-0.48324955,0.0025711823,1.0400863,0.16464381,0.88518757,1.4737648, +0.38909397,1.171041,-0.32656097,-0.008209882,-0.5226194,1.0429776,0.41409135,-0.50723445, +0.15466884,1.0415684,-0.03926799,-0.9489328,0.13191175,-1.9805655,0.76877064,-0.4213276, +-0.46931073,0.8756957,-1.3651628,1.9470986,-0.48024204,-0.52325094,1.0212247,0.7086953, +2.4512298,-0.21120599,-0.120406635,-1.479316,-0.33210227,-0.7214313,-0.448767,-1.7441877, +1.6606076,-1.4166034,-2.8022027,-1.1884245,-0.6038396,-1.149554,1.0983036,-0.13783918, +0.025385605,0.61039174,0.28601253,0.9785673,-1.1094775,-0.5475181,0.66596717,-2.5345545, +-1.3751845,0.50099224,-0.48024905,0.9361076,0.8091803,-1.1980929,0.4066571,1.2016978, +0.1474344,-0.97746485,0.87938994,0.63542455,0.54261076,0.71593887,-2.994613,0.8809376, +1.8081318,0.43663847,0.192729,0.69643867,0.33822548,0.65178126,0.0014710003,-0.76670486, +-1.0043228,-0.9981917,-1.3730426,-1.067742,1.7612661,0.7540957,-0.6250274,-0.3903927, +0.11255753,-0.65554506,0.067516856,0.77760416,-0.035742734,0.33601573,0.88649154,-0.27213177, +-2.051816,-2.7816176,-0.38553995,-0.7150961,-0.65866506,0.73568,0.12661266,3.999392, +-0.92730594,0.030181527,-0.93402994,-2.0779161,1.015371,-2.0726008,-1.7224298,2.0186472, +-4.125478,1.3149867,-2.923615,2.06105,2.2933798,-0.3885297,-1.9675268,-1.7995086, +-0.70256805,-0.46260026,-0.56759036,0.04682108,0.79200155,-0.85891926,-1.0061638,0.08046973, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.2847906,-0.30937758,-0.02852887,-0.32473028,-0.52886987,0.17371185,0.5665453,0.14630444, +0.49872696,-0.7379318,-1.2037352,0.4170435,0.6878814,0.049857266,1.3480358,0.9076988, +2.6805708,-0.20080851,-0.9988488,-0.7401368,-0.5654978,0.4760314,-2.1580687,1.3185511, +-0.23929659,-0.24679355,-1.0793432,-0.11422555,0.013239767,-0.12194493,0.33905926,-0.58963203, +-0.8958158,0.5483281,0.09866745,0.19718106,1.0590272,-1.0225644,-0.85524046,1.2572197, +-1.4828833,-1.3094121,0.81786186,0.23820019,0.105232134,-0.09165941,0.031267546,-0.09211212, +1.3554426,-0.39814812,-0.16137354,1.7944489,0.027509702,2.2320163,-0.1049797,1.367415, +-1.655344,0.15364446,-1.5844736,0.8444543,-1.2128679,0.28376955,-0.28219587,-1.1582032, +-1.61936,-0.51104045,1.7406294,-0.29348505,0.91722155,-0.057042867,0.87672675,-1.8269113, +-0.40318832,0.94940555,-0.16325495,-0.086455286,-0.4304619,1.1493794,0.29751435,0.044022277, +0.64305454,0.58822495,0.21258704,1.5470315,-0.060287535,0.27808106,-0.64295256,0.15011522, +1.5877615,-0.6432576,-1.1335928,0.99675965,-0.14876615,0.0960042,-0.045113303,0.079121724, +0.8505307,-0.8391242,-1.0117741,0.084968135,-1.6064397,-1.3730536,1.8666831,0.75746834, +-0.010056471,1.238007,-1.0405992,-0.31560314,0.6234536,0.8906717,0.51291686,-2.5412388, +-0.96808213,0.4770681,-0.3559515,2.5402317,0.9265583,0.55808187,-1.1169496,-0.03529674, +0.24120396,1.1277837,0.8811311,1.0329891,-0.923912,1.4121517,-1.3804307,-0.53591454, +0.9798864,-1.1332853,0.42590374,-3.0803738,-0.66169095,-1.1098778,-0.31572723,0.71667963, +1.6409252,-0.26382387,0.25382257,1.6378108,-2.379856,0.18126236,-1.5385789,-1.1564229, +1.7435231,-1.1726068,0.4755114,-2.7746863,0.11258662,-0.05290118,0.40425268,1.1107234, +0.6519424,-1.0436192,0.24687822,-0.9495615,-1.6611001,1.1551828,-1.6656845,-1.3863657, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 + +==== +name:CrossAttention_DiffSequenceLengths_UsingDMMHAInsideMHA.query_data +0.43077114,-0.14989159,-1.0060369,-0.82154983,-1.5482544,0.5319746,1.2605689,-0.100393504, +-0.4003488,-1.472323,0.9132019,2.2113044,-1.7974558,-1.0634329,-0.679593,-0.5643179, +0.22734594,1.6142496,1.0085973,0.52759737,-0.7239287,-1.1196282,-0.7967753,1.5480669, +-0.0617433,-0.44683626,-0.18375573,0.8246182,-1.3128496,1.4148741,0.15647626,-0.21634398, +0.44284612,0.21839707,-0.34419647,-0.25271067,-0.86886257,0.6563907,-0.5319938,-0.9562584, +0.16586353,1.3291413,-0.048344623,-0.60810125,0.40389603,1.9367125,-1.4519055,0.38220277, +0.20508662,1.1615338,0.99090916,-0.1867091,-1.6845173,0.8065638,-0.8351927,-0.9467404, +1.1483506,-0.9108504,1.4028448,0.33584473,0.3191184,0.30726478,-1.6384237,-1.7763886, +0.21555306,0.56800735,0.08261103,-0.8215345,0.018922104,-0.082034156,-0.9571581,1.0139722, +-1.7302761,0.58874243,0.38432342,1.0097119,-1.0053118,0.10140715,2.171165,0.66207427, +0.10058121,0.53916126,0.08617684,2.190898,0.9836362,-0.08561496,0.25233144,-0.390798, +1.2098501,-1.4061048,-1.6047385,1.4587147,2.1531198,0.4683049,0.11273794,0.6572677, +-0.64705354,0.17124355,0.038908705,0.62656426,-1.5579985,-0.5070348,0.8449956,-0.67559385, +-0.99336135,2.042072,0.038118,-0.57891816,-1.6923704,0.72934633,0.69913614,-0.2987596, +-1.1022302,-0.024549423,-0.8358561,-0.9420936,-0.10321275,-1.0513904,0.24664895,0.60799253, +-0.83963245,-1.3682451,1.5612797,-0.94027025,-0.6599427,0.21301717,0.59936935,-0.2563169 + +==== +name:CrossAttention_DiffSequenceLengths_UsingDMMHAInsideMHA.past_key_data +0.46079433,-0.40098616,-0.97117066,1.4263169,2.4884417,1.6959696,0.14180663,1.8334354, +0.3557035,-0.47728628,0.46637958,-0.09439251,-0.9831182,-0.898322,0.8020517,-1.846532, +0.60413677,-1.6295836,-2.1211765,-1.8388466,1.966764,-0.19623396,0.08658318,1.419255, +0.9341797,-1.3915052,0.86900634,0.18418126,-0.34167808,0.024290914,1.279812,-0.8859665, +0.40088567,-0.009657237,-1.7971646,-0.8022532,0.19321355,1.2973421,1.001331,0.5972125, +-0.81527567,1.801214,0.21524046,-1.0063655,-0.18290497,0.8962484,0.0076174983,0.88686466, +1.103694,0.4005307,-0.8577026,0.13545467,0.045165855,1.8593464,-1.6263219,-0.13482246, +-0.5840936,0.33510563,-2.4375644,1.1149246,0.013748487,-1.8447012,-0.36111313,0.60896236, +-1.5914478,0.0032222164,-1.0574737,-0.55598503,0.026738383,0.18345025,-0.4707425,0.2727964, +0.8179776,-0.27891427,1.4315678,1.4622141,-0.42870206,-0.63784057,-1.664173,-0.12656933, +-0.36343777,0.77905124,-1.5096616,-0.2773914,0.9687444,-0.7303571,-0.7623615,-1.4469403, +2.6205738,-0.7474732,-1.3003469,-0.8038504,-0.7742951,-0.26938978,0.8253722,-0.29832315, +-0.9228233,-1.4513385,0.021857359,0.042539075,1.5309323,0.092447735,-0.099008314,-1.0506538, +-0.30595258,-0.43847445,-0.37016416,-0.9592554,0.5383296,-0.14244542,-0.20035347,-1.7140461, +0.4936441,0.48701534,-0.8391294,0.99012136,-1.3647583,-0.021869909,-0.27120733,-1.3171748, +0.18970262,1.7025702,0.06763423,-0.46302176,0.44702417,0.10572,0.027762132,-0.4255422, +1.4219756,0.45636335,-0.52867067,-0.10800384,-0.7408667,-0.60829115,-0.64072573,-1.1343116, +0.777277,-0.29104146,0.5541276,-0.6701259,-0.060362495,-0.7110406,0.71966815,-0.2484193, +-0.7308736,-1.6417032,0.27566653,-0.70838505,-0.015779218,-0.4917301,0.9541896,0.54414475, +0.4472121,-0.6161211,0.46629006,1.7148316,-0.83218604,0.17233914,-1.649217,1.3985621, +-0.39791209,0.7825789,-1.7232282,1.7975394,-0.35687152,0.54565734,0.1508182,-0.25547078, +1.6857923,-1.6480463,0.29871365,0.91064566,-0.029856121,-0.11817078,-0.14268771,-1.2276365, +0.038127385,0.51271755,0.068599224,-0.2722761,-0.48972502,-0.27929667,1.2577442,-2.0866349, +0.040071458,-0.3277549,1.4558079,0.055492226,1.4849256,-2.12389,0.4595849,0.28005785, +1.3905339,-1.6413486,-0.15503581,0.06606026,-0.4957955,1.2165778,-0.33868217,2.0347626, +1.0541779,0.9508337,0.559299,-1.0636955,-0.43109635,0.57275134,0.67755705,1.3071839, +-0.46744102,-0.8601534,0.8591042,-0.8096266,0.8733118,1.1997361,0.45615304,-0.35757902, +0.041082226,0.5934659,0.010185518,2.1982963,-0.9906709,-1.0026686,-0.9768954,-0.58957994, +-2.1789315,-0.6296504,-0.6532847,0.078514025,0.41780058,-1.2402164,0.9000542,1.8022423, +-0.20828511,1.5743712,0.1989895,1.9887319,1.1172835,-1.5639046,0.01862737,1.054325, +0.030546581,-0.03688353,1.2697648,-0.7098542,0.017515613,0.32362577,-0.33379096,-0.020129103, +0.7750233,0.43283764,-0.80871755,-1.104124,-0.7891022,0.0012484558,-0.15993978,-0.8319575, +-0.59815043,-1.5200393,0.4178537,-0.040018726,-1.2597873,0.028620504,1.342622,-0.7399359, +1.3151376,-0.32345748,0.19782817,0.097750805,1.4015235,0.15843384,-1.1419014,-1.3109704, +-1.5329211,-1.7119702,0.04613506,-0.9583745,-0.08081161,-0.70385903,-0.7707843,-0.48084533, +0.70358557,0.92914516,0.37117255,-0.98982257,0.6436313,0.68889666,0.2746472,-0.6036204, +0.70885956,0.42281857,-3.1168566,0.64445204,-1.9137427,0.6635616,-0.1540724,1.1936116, +-0.09816121,-0.88661426,-0.14735366,1.0598063,0.026246618,-0.11433516,0.7435535,0.21035936, +-0.005927406,1.36606,1.555114,0.61332625,-0.28595915,1.496911,1.1831195,0.71889716, +-1.2160766,0.14067191,-0.7436722,-0.15901226,0.24005693,0.10015941,-0.4751751,1.2729537, +-1.6961312,0.73018354,-1.8574833,0.38259813,-0.8869043,0.87830377,0.08645252,0.24770638, +-1.0182793,-0.65457016,0.2072174,0.58356994,2.9290962,0.22285832,0.9760375,-1.5569339, +-1.3298919,-0.35549477,-1.1974277,1.4863993,-0.4102187,1.3821819,1.4867824,0.04277972, +0.50179976,-0.056099474,0.538437,0.48334184,-0.12364963,0.50496995,1.7236962,0.7130162, +0.3257996,0.124769524,-1.0126731,-1.0272969,0.32335654,-1.3693911,-0.7663276,1.2815113, +1.9142298,-1.665956,1.6266496,-0.2114383,-0.0150050875,-0.11341163,1.0805441,-1.6076766, +0.45616361,-0.9448702,0.5707885,1.5427964,-0.0004173264,0.37415507,0.40955177,-0.7995935, +1.5116394,1.7064682,0.70178336,0.07328543,-0.46189383,-0.62649024,1.7108365,1.414415, +-0.063661486,-1.5799305,-2.832012,-1.0834267,-0.13062039,1.400689,-0.6516562,0.50481546, +1.3031809,0.12853631,-0.14244787,-1.3087635,-1.2024753,0.41609964,-0.20090753,0.12253132, +-0.047277715,0.66414404,-0.7846874,-0.33558065,1.8961822,-0.79978615,-0.28157544,-0.5893867, +0.44478136,1.0223923,-0.49821162,-0.43141434,-0.2789816,0.5298338,-0.7393953,-0.37595996, +-2.3721938,-1.381745,-0.11244375,0.89786416,0.29507577,-1.0987685,-1.4002562,0.1746801, +-1.6528037,1.0659268,0.063896194,-1.6073202,-0.9659539,-0.7243113,-0.7731925,-1.489933, +-0.8746625,-0.6844016,-0.71128577,1.1279566,0.10482781,-0.9932572,-0.3346216,-0.8795571, +-0.30000666,0.87550914,0.2522708,2.2856011,0.37592742,-0.9135945,0.8097407,1.0799313, +1.094167,-1.0942409,-0.14763741,1.131812,-1.684729,-0.49941677,-1.4269377,-0.9325702, +-1.0124571,1.2505698,-0.23453803,-0.8633556,-1.0356058,0.14166717,-0.0111356275,1.3440744, +0.5000167,-1.4317977,-0.6289807,1.0700725,-0.6210827,1.7345722,-1.0982895,0.57261336, +-0.86121553,-0.50959516,1.0985817,-0.12706716,0.81345224,0.4732906,0.75386566,-0.8881882, +-0.2215744,0.42425263,-0.8490729,1.6295,-0.77722806,-0.3000036,-1.006559,-2.1433082, +1.7969185,-0.20433894,-0.44791484,-0.19871506,1.4198639,-0.9651066,0.6795679,-0.42378825, +-0.59667087,0.5670582,0.9882406,-0.51390296,-0.76884913,-1.1690958,1.1035038,-0.575256, +-1.8491307,1.4099522,-1.3698595,0.77946055,0.18342865,0.28791544,-0.58437526,0.36559147, +-1.6677799,0.5880377,1.55701,0.8840272,-2.01954,-0.984209,-0.18779492,0.4869373, +-0.10665268,-0.4932144,0.5953003,1.1641518,-0.23229401,0.7289299,-2.5790508,-0.93750936, +-0.32125893,-0.48856622,0.3327982,1.0137506,0.50666904,-0.62222546,-1.5227681,0.5569641, +-1.8381767,0.6530373,-0.18844908,-1.175835,0.2872573,-0.0028761027,-0.036597293,-0.0842233, +0.4195241,0.924434,0.4966152,1.0121332,-0.04413972,1.6184593,0.57110983,-0.543694, +-1.0938951,0.20579681,-1.3065215,-0.973376,0.23908707,-0.60788745,-0.93331623,-0.034475047, +0.072677895,-0.20583403,-0.3775469,0.85464275,0.34242734,-0.22342612,2.4643219,0.19383174, +1.1320051,-0.560981,-1.3629409,-0.7917565,-0.26800978,-0.4966082,1.3363862,-0.120041125, +0.46146888,-0.046481155,-0.43355432,0.037996013,1.7140515,-0.76794857,0.7669904,-1.0260073, +-0.45962644,0.0035832059,0.3263751,1.4831287,-0.050082643,-0.8436156,0.650042,-0.3641698, +0.23868157,-0.11622244,-1.9434569,0.5082992,0.583368,0.92660475,1.8004627,-1.1951038, +0.51650745,0.409295,-0.419082,0.39710623,0.49964696,-1.2186838,0.24622276,-0.9179843, +-0.6518565,-1.7747449,-0.47336093,-0.20357068,0.54985684,0.00089992664,-1.5422882,0.86214805, +-0.11858662,0.4883706,0.9659361,1.4226048,1.9612269,-0.07223876,0.31112444,-1.078361, +1.0616002,-1.1848874,-1.8052517,0.830386,-0.5216965,0.77760726,0.40807465,-1.6300026, +-2.7196794,-1.0966017,0.016491488,-1.2217764,-0.65276146,-1.4589407,0.16987796,0.09082593, +-0.48139262,1.3970653,1.497715,0.5652672,-1.7997712,-1.1046902,0.40713033,-0.62855756, +-0.48709142,0.8989674,0.5108748,1.3141544,-0.4292093,1.3752254,-0.55413127,1.4994915, +0.10583464,-0.86050975,-1.6312195,-0.3014723,-0.2562327,0.8576619,-0.1105905,-0.43243197, +1.0770375,-0.22482656,-0.5762418,0.5746089,-0.48982823,0.65880215,-0.5969171,-0.22295918, +0.15217698,-0.37412632,-0.013451469,0.81547195,0.4106018,0.48096985,-0.63543046,0.85282975, +0.66956234,1.0044192,-0.7263658,-0.1724586,0.6335339,-0.60881513,-0.22612247,1.9258057, +1.951761,1.2399405,0.93858516,-1.0192511,0.5125622,-0.35911658,-1.0585719,-0.50900584, +0.11566507,-0.5473556,-0.5507994,0.7920415,0.14410649,0.23345809,0.1118724,-0.67570317, +-1.370572,0.3105647,-0.5070366,-2.0107822,-0.39256725,-1.0922179,0.69865024,0.5216252, +0.49689314,-0.6650416,0.7315516,0.3196498,-0.40985453,-0.45333743,0.8927082,-0.47360405, +0.30365646,1.033957,1.9093426,1.6638731,0.90082276,-1.5059114,-0.6890484,-0.5480872, +1.6531498,-0.69931793,0.38616636,0.10086706,-0.9351272,0.38182402,0.3982961,-1.2557749, +1.2228775,-2.08651,-0.59075713,0.9719703,-1.1932578,0.35026592,-1.2963604,-0.09302414, +-2.3137732,-0.8425717,-1.5429214,-0.40176374,-0.4152314,-0.67366415,0.7979132,-0.8868796, +0.63438666,1.6292758,0.13906415,-0.8576702,-1.2493385,-0.7097851,0.7046427,0.15559073, +0.93679523,0.7703309,0.14081065,0.47348827,1.8552462,1.4156562,-0.30274603,0.98967946, +0.58585083,1.1363881,0.67161655,-0.9741674,-1.6196846,0.572627,1.9026182,-0.7756641, +-0.18808974,-1.0357478,1.1778295,-2.305167,-2.2636602,0.3750199,-0.082343645,-0.47962302, +-0.3010948,0.5369879,-0.413804,-1.096925,-0.9273629,0.88833886,-0.52474195,-1.3852776, +0.10217833,0.50499475,1.3289608,0.21790339,-0.65971124,0.47400787,0.7271749,-0.038905308, +-0.04459939,0.2601329,-0.069856495,0.2501139,-1.0219133,-1.1504377,-0.83611137,0.64221096, +0.25879756,1.040239,-0.18669093,-1.1436414,1.1445535,-0.018767055,1.283455,0.59794647, +2.1886187,-0.21977298,0.90072393,0.8913641,-0.55512637,-0.17248231,-1.4617383,-1.5487962, +0.1265688,0.7930071,0.63802403,0.3400246,0.86301714,-0.5896978,-0.27253276,0.7375215, +0.43311873,-0.21018882,1.3207943,-1.2920012,-0.51867867,-0.28339776,0.8165349,0.002385198, +-1.2614918,0.5140042,1.0875463,0.73930454,0.61915493,-1.8743135,-0.8998865,0.4820806, +-0.054888185,0.5225576,-1.2663426,-0.061494764,-1.389781,-1.9536786,0.29577908,0.8425888, +0.24561642,-0.03299648,-1.5620143,1.0061071,-0.044044897,1.9595621,0.9423143,-2.0051255, +0.7550497,-1.3965353,-0.7594955,-0.25075668,-0.09406245,0.39756522,-1.022855,-1.150692, +0.6006052,-0.013250268,0.17437305,-2.1936834,-0.17713739,-0.8907292,-0.9206264,0.9219348, +-1.0956712,-1.0928966,-0.3310106,0.45028883,-0.8840147,1.2341441,1.4498476,-0.8814471, +-0.24508175,-0.7786755,-1.6853821,0.30301106,0.7335949,2.0118642,-0.8974095,1.336235, +1.3423537,0.19785331,0.6021635,0.8732731,1.9741,0.47780856,-0.060137887,-0.8661688, +0.30532077,1.0241649,0.24461035,-0.77992326,0.089076206,-0.12915348,0.26473877,-1.6618484, +0.55078864,0.59542316,0.44485343,-0.0037628172,-1.8059362,-0.019322792,1.060715,-0.8601289, +-1.9892695,-1.540558,0.3140257,0.37287602,0.8862932,-0.055258997,-1.5003284,-0.81850415, +0.8188394,0.14049591,0.6498296,0.4347888,-0.20496055,-0.17400683,1.8571023,0.41467425, +-0.12858754,0.45542,0.22290581,-2.1573563,0.6500845,1.8209393,-0.7802799,1.4540358, +-0.2568697,0.2934714,1.0703601,-0.72000146,1.2424939,-1.2142173,-0.87515473,-0.59352034, +0.66200536,-0.3408744,-1.5199745,-0.21653287,-0.7842214,0.7312936,-0.34323505,0.07077408, +-0.40547246,0.43393898,-0.18359077,0.3251987,-2.5933886,0.09725088,0.41391367,-0.19928005, +0.66939247,0.73860705,1.3042139,0.10481161,-1.9138007,-2.2854993,-1.601841,-0.03790706, +-0.15730529,0.27623984,-0.6252459,-0.73649114,0.5550479,0.65592444,-0.25665015,-0.038476657, +0.40431434,0.50434357,-1.1439807,-0.71957386,-1.230546,-0.5069066,0.8123336,0.54627186, +-1.0980979,0.51226676,0.08584311,-0.4939267,-1.4064597,-0.17482337,0.679944,-2.1630976, +-0.3961232,2.2542837,0.67263675,0.2598325,-0.7371852,-0.6783298,-0.083288394,1.6028637, +0.4655892,-0.8721584,1.176787,-0.2925942,1.6973464,-0.566603,-1.0032657,0.17462958, +0.982327,1.0374448,0.15919177,-0.9880967,-0.5053407,-2.018282,-0.9131215,-0.17845681, +0.38900214,-0.33945432,-0.056979056,-0.39618546,0.7510253,-0.89911294,0.8375479,1.9608808, +0.47278965,-0.5270916,-0.53627014,1.2098372,-1.1265894,-0.95380443,-1.1644485,-1.2785138, +-1.0448164,0.78990495,1.1022825,-0.6970731,0.20733404,0.7591567,0.100564204,-0.95494276, +-1.4704018,1.0104276,0.4961794,0.5769559,-1.107647,0.23497719,0.6289996,0.31403384, +-0.7450232,1.0122606,-1.527632,0.92874193,1.081056,1.5723304,-0.3424922,-0.99943, +0.79388034,-0.6992153,0.04399551,-0.3174622,-0.90207195,0.32099947,-1.3920159,0.5922057, +-0.9669311,-1.7317313,-0.05010746,0.43163386,0.5769346,0.8183537,-2.3536403,-1.0051445, +0.1066523,1.5190033,0.7837445,1.90134,-0.5249394,0.27441698,-1.0999708,-0.40435222, +-0.7352957,-0.6339887,-0.39344913,0.00271754,0.022212664,0.54345345,0.13998847,-0.34404564, +-0.52257854,-0.3071317,-0.44903713,0.49097106,0.8655252,1.2740445,-0.7977028,0.4693722, +-1.3946797,0.37317473,1.0826722,-0.14958951,1.072636,-1.1385679,-0.8886453,-0.13580984, +1.0222104,-0.41742945,-0.4535531,-0.99162835,0.20288104,1.2466952,0.70068014,0.6966507, +-0.20697448,-0.5633094,0.6772459,-0.031911075,-0.17360823,0.8982406,-0.19778745,-0.83777624, +0.9091885,0.08071989,-1.0370294,-1.1129059,0.095411874,2.3374097,-0.3928206,-0.33627385, +1.5237712,-0.0572812,-1.4484669,-1.5727965,1.226664,0.66635454,0.8261257,-0.057756558, +-0.72671205,-0.21716312,0.13603121,-0.83831114,0.5614499,-1.2595961,-0.33275875,-0.20400788, +-0.69101983,-2.2055054,0.44786966,-0.7557508,1.3257079,-0.34198228,-0.5413596,0.09152195, +1.0534397,-0.56340766,1.0147377,1.4403037,0.9903228,1.6264315,1.292646,1.5148823, +1.6043264,0.20806953,-0.4292239,-2.2622437,-1.3227332,-0.4482828,-0.3817351,-0.15279447, +-1.0007604,-1.5957776,-0.13022317,-0.18941793,-0.80755407,-0.74215215,-0.9401566,-0.39652374, +-0.8563028,1.2598753,0.24099673,-0.97231793,-0.28044778,-1.1802856,1.0121683,1.3841867, +1.252002,-1.1446927,-0.09126702,-0.40157068,0.5620131,-1.0079098,-0.6758917,-0.41321704, +0.15328847,0.6941287,-0.3287277,0.66396505,0.8220764,-0.21321523,-1.2456582,-1.1711904, +0.59172696,-0.47622442,-1.7126293,0.61295235,0.12955453,-1.4059671,1.17942,0.836636, +0.13874525,-1.2743194,-1.4023305,-0.3070685,-1.7139153,0.40508026,-1.4108233,0.16491273, +-0.28813145,0.71178526,-0.9379476,0.27372944,-1.3948402,0.7955496,-0.114961766,0.49585068, +-1.3205253,0.49908426,0.3062034,0.3636979,0.31263396,-0.19346388,1.2412993,-0.15589799, +-0.7391692,-0.05872619,-0.95051795,-0.4639964,-0.17724662,-0.37955412,0.19939707,1.9457614, +0.57094985,1.0723007,-0.50370944,-0.5870163,-0.37817806,0.8528891,-2.1481185,-1.0331647, +0.10233585,-0.22409236,1.9677297,0.44768322,-0.66219145,-1.577607,-0.34056005,-1.30322, +0.46675065,0.16110632,0.32003194,2.0791767,-0.907466,-0.19240421,-1.2125157,-0.08059852, +1.5932736,0.5687224,-0.114487045,0.25163025,-1.2108556,-0.3937337,0.085252576,0.099421985 + +==== +name:CrossAttention_DiffSequenceLengths_UsingDMMHAInsideMHA.past_value_data +-1.5306163,0.3276232,0.2791965,-0.3770512,0.004174999,-1.4834915,-1.4797956,0.13468726, +-0.6677232,-0.01155552,0.83949065,-0.17392993,-2.810668,-0.15065365,-0.48104402,-0.23469436, +0.8997308,-1.5785302,0.24395663,1.5703039,-0.6259431,0.4723279,0.9663058,0.21023144, +-0.685097,-0.709521,0.74380016,0.5921491,-0.7864684,-1.1764731,-1.2808067,1.6616518, +-0.06794512,2.3602285,0.5555456,0.43952233,0.30627248,0.99914986,-0.9660632,2.1600132, +-0.100301705,-0.7034001,0.302561,1.0923389,-1.0075549,0.5668694,-0.71644413,-0.5062735, +-0.48948243,0.76354146,-1.1090727,0.1926161,-0.34341785,-0.84721017,-1.2135236,-1.2028884, +-1.633796,0.8961672,-0.24165316,0.15865193,1.1781894,-1.2201172,-0.94154567,0.25471553, +-1.8240795,-0.5787085,-0.9248931,0.32952243,-0.42581588,2.0081494,0.93789136,-0.85323846, +-0.38731343,-0.34758452,3.3065743,-1.5101997,0.2035397,-2.0844321,-0.0069374414,1.9098905, +-0.40845543,1.1045544,-0.06611522,-0.4224987,-0.25165635,-0.5869026,-0.6260583,-1.3301944, +1.5068008,-0.3930764,0.2937743,-0.87653184,1.1169906,-0.2735558,-0.09103267,-1.8289766, +0.39597622,1.8115057,-0.86907756,-0.45822915,-1.1383239,0.12916218,0.064024195,0.7050811, +0.55147356,-0.81251603,0.22494805,-0.3283011,-1.091033,-0.12685588,3.8016603,2.3151705, +0.1398266,1.7388572,-0.045383364,-0.053138338,-1.9495717,-0.96010554,-0.78349924,0.10751903, +0.013984535,-0.57894236,-0.5888132,-0.16615313,-1.3814117,-0.61263853,-0.38128987,-1.2489489, +-0.3302379,-0.83480716,1.2353824,-0.2438038,-0.18954566,0.4280281,0.55696833,-1.7362418, +-0.37678412,-0.90903234,-0.14517024,-0.53633255,0.15706946,-0.9804593,-0.56776726,-0.59115964, +1.0825914,0.36800367,0.3688887,-0.28631827,-0.38471785,0.5610029,0.77743393,0.015146785, +1.1416479,1.274155,-1.664698,0.43037888,-0.042601928,0.38828883,1.1159766,-0.9205382, +-1.6202741,1.1061915,-0.9984847,-0.6862195,0.2046209,-0.6861018,-1.5922107,0.034189768, +-0.78148466,0.59785986,-0.5060766,-0.68844616,-0.21000054,1.0521535,0.9079041,-1.0932262, +2.7997077,-0.32577634,-1.1524158,0.888232,-0.36167246,2.1537194,0.84740835,-0.19871984, +1.5753069,0.8491152,-1.2288952,0.8883941,-0.5164874,-0.08332629,0.13105445,-0.87909603, +-1.3333423,0.36778402,-1.3882335,-2.5752027,-0.8361056,0.33109242,-0.26988113,1.267131, +0.18375349,-0.7663097,-0.43958354,-1.4365413,1.0857972,-1.3811,-0.92040765,-0.16028622, +0.0023532645,-1.5026504,-0.9055358,0.2650406,1.1297233,0.34900355,-0.025809761,-1.5624087, +-0.61734235,0.52149427,1.0809467,0.8893759,0.13807164,1.2046005,2.8814607,-0.59386194, +-0.7631158,1.5184829,0.23546453,0.11230769,0.39237434,-0.6544865,-1.0347953,-0.77714753, +1.2459463,-1.4366406,0.49865463,-0.55768746,-0.35336688,0.742951,0.8439889,0.34297654, +-1.8731197,1.5709647,1.3101965,0.09143683,0.010257817,1.8014492,0.94722426,-0.029294403, +-0.29233867,-0.19353712,1.177232,1.0399917,-1.613423,0.4646424,0.8641213,-1.5064632, +-0.0029647513,-1.7770436,0.12949283,-2.0832345,-0.6817455,-0.6110659,-0.70884985,1.4515281, +0.53551054,-0.39956886,-0.9330778,-0.23877631,-1.0291129,0.97308,1.996766,1.0531999, +0.33169034,-0.16562878,-0.40510628,1.7452846,-0.5759356,1.5610986,-1.1315392,-0.29623166, +-1.7140566,0.1592342,-1.2637277,1.6650494,0.41227227,0.5373967,0.28267846,-1.0925409, +0.12411829,1.8370807,0.008554926,-1.0170162,-1.8523426,-0.713327,-1.7622288,0.83051735, +0.78116727,-0.8756818,0.6139813,-0.57645464,-0.045614284,0.37195554,-0.44396,0.41820335, +-1.6857281,0.11747499,-0.034952022,-2.0463932,-1.8096902,-1.8595237,0.41430682,0.12395962, +0.27395758,-1.3263785,1.1389738,0.9828412,-0.76696306,1.1760603,-0.2509224,-1.7762051, +-1.6326947,0.73372346,-0.10404881,0.88122493,-0.088373125,0.2676709,2.1235263,1.396849, +-0.43282726,0.37496874,0.49444544,0.76139116,0.07100881,-0.49353185,-0.0036228173,-0.4802871, +1.6833673,1.2407262,-0.20361502,0.42829227,-0.16545926,1.1932411,1.0488805,0.56861085, +0.8712643,0.6605708,1.1740619,0.5311314,0.15190053,-0.5772256,-1.5717508,-0.02784838, +-0.74105555,0.060009066,1.1404884,0.17282468,-0.41500166,-0.8531286,-1.4301353,1.3328053, +-1.776691,-0.93478304,-2.313202,-0.31614158,-0.34228456,-0.40429443,-0.0631299,-0.8212651, +-0.91365564,1.8178264,-0.33406293,0.90765864,-0.8367711,1.6127286,1.5141821,0.23101868, +-1.0995317,0.08700138,0.0473045,0.23962392,-0.97822064,-1.5230001,0.16236304,-0.010291317, +0.0020750219,1.0268006,-1.4751605,1.0106937,-0.74322754,-0.39522207,-0.8257794,0.08961986, +-1.9058179,-0.56808573,-0.51575655,1.2639302,0.15069814,0.6955183,0.0059388145,-1.0489004, +0.90720487,-0.84544134,-0.5262433,0.18209977,0.9455388,-0.20138454,1.5105247,-0.5714784, +0.6655893,0.0036163009,1.5466719,0.21440601,-1.8773128,1.0883352,-0.08154851,-0.5530619, +1.2229648,-0.33130863,0.59998673,-0.7683833,-0.83613014,1.8105818,-0.7870327,-0.5847709, +-1.7083207,1.6299822,0.39799833,0.23777963,0.9751384,-1.3293365,-0.5410468,-0.091437735, +-1.5484711,1.3114271,-0.01842905,-0.32328865,0.23622549,-0.7525823,0.045113005,3.4275386, +0.604682,1.6683111,-0.3550831,-0.751569,0.3097036,-1.341705,-2.3069577,0.7315925, +0.64133817,0.8338512,0.028169874,1.9783727,-0.08732819,-0.55396473,-3.0064988,-0.047165867, +0.83187777,0.0068611987,1.1242217,2.294881,-0.17335021,1.2312535,-1.5858526,1.0313191, +0.06349048,-0.2213905,-0.16339892,-0.15630347,-0.3088029,0.19867297,-0.17429213,-1.1557925, +0.41705388,-0.60786796,1.0479866,-0.033826966,0.12702395,-2.049232,-1.2566801,0.9396144, +-0.73381674,-0.5324377,-0.27793998,1.3637426,0.374138,1.3102646,-0.2677478,0.21317627, +-1.2032435,1.1780312,0.1086482,0.0441291,0.33831555,1.4467921,-0.21449511,1.663039, +-0.85152256,0.42218462,2.0092185,-0.48981473,0.24525586,0.87750506,-0.1378997,-1.5003532, +-1.0559593,0.5809326,0.8915153,0.7845553,1.146432,0.07198519,0.20823318,-1.5188687, +0.31732896,0.6126808,-0.5832113,0.6440017,-1.8158889,0.7510996,0.30028433,2.1106086, +1.4130856,1.5069803,0.8173971,0.6466156,-1.1816313,-0.3350913,1.8267285,-1.4561645, +-0.45028183,-1.419234,1.4509518,-0.56578135,1.5445343,-0.41376248,-0.5041321,1.2785292, +0.93883175,-2.7162802,0.4511408,0.60016686,0.20980693,-0.657658,0.028408445,-0.39806148, +0.21132302,-0.20239426,-0.62192816,0.16377045,0.8024389,0.2890059,-0.5536424,0.33625403, +1.0697924,1.5954041,1.2075526,0.5373802,-1.009124,-1.3655528,-0.20238121,-1.4091848, +-0.78478473,-0.17012231,-0.48421043,-0.32791805,-1.3280046,0.23146676,0.99650806,-0.5481375, +0.72575533,2.6627266,-0.09181103,0.65121,0.19677009,0.96962374,-1.7186499,-1.0569568, +0.14346392,0.8869626,0.13052402,-1.6645732,-0.8236133,-0.7947061,0.38899195,-0.76203895, +-0.6808071,1.0847476,1.3353163,-0.4132748,0.42490268,-1.8814838,0.19832706,1.189978, +0.5267817,0.101060845,-0.38864297,-0.646792,-0.17908241,-1.5514412,1.610459,0.56421065, +-0.102437034,-0.6198048,-0.07033962,0.79779494,1.0114479,-0.90369093,-0.97352874,2.07823, +1.1365929,0.70851994,-0.13864625,0.92402035,-1.2732332,1.5317684,-0.035772223,0.7908615, +0.64621776,-0.1315709,-0.17536636,1.2215831,1.0264974,-1.7722311,-1.6924057,-0.94622064, +-0.8935454,-1.1185259,0.27211064,-0.46370444,1.2061247,1.4528778,-0.028683238,1.683458, +0.02421431,-0.43479064,0.06478574,0.94486,-1.614461,-0.20859933,0.29740566,0.36308467, +-0.36843634,0.48878574,0.29212162,-0.5919081,2.1815987,0.4395502,-0.33118334,-0.57171905, +1.0294089,0.10205979,2.5481126,-0.4359241,-1.242607,-0.02769846,0.17506745,-2.1184506, +-0.30916852,-0.36841545,-0.36876354,-0.6302257,-1.3431926,0.75803804,-0.58384085,-1.0237014, +-0.75993425,-0.47232324,0.10864712,0.668339,-0.9531795,-0.4792974,-1.3455077,-3.3923, +0.15579394,1.5200036,0.5220833,-0.50705993,0.09647914,-1.1748201,-0.122292355,-0.42770925, +-0.85271424,0.40565223,2.599867,1.6654495,-0.07207302,0.8841147,0.86270744,-0.647538, +0.6439041,-1.4409921,-0.8052984,0.23875287,-0.41478765,1.7564787,0.6480404,-0.38203812, +-0.4705797,0.1869706,-1.0555313,0.59561193,-1.375302,0.6230102,-0.16459472,0.41461352, +-1.0125859,0.24498521,2.4123478,-0.45721674,0.31739986,1.505567,0.76170415,0.43188548, +-1.0136893,-1.2775884,0.053432442,-0.46323586,-0.019058215,0.20565668,-0.67642784,0.494103, +1.8585562,-1.009341,-0.46954635,-0.04961066,1.1404597,-1.186382,-1.0651481,-2.163661, +-0.44036222,0.68014574,1.0652248,0.35715365,-0.600957,0.7064716,0.2043186,-1.9207056, +-1.2280948,1.5118653,0.3222051,-1.3747944,0.8199531,1.061435,-0.43503404,0.6576821, +-3.7401006,0.9735768,1.1751554,-1.1247027,0.2820854,-0.33812055,-0.10252948,-0.42488045, +-1.3322954,1.8904037,-0.31031084,0.104755044,-1.0094006,-1.0368671,0.4125984,0.5263921, +0.87792414,1.103774,-0.21020754,-0.44420308,0.74681383,-0.6374392,0.8717585,0.37450027, +1.1550264,0.6703917,-1.0544459,-0.86563367,0.7324853,1.9070559,-1.3228117,0.023211604, +0.28167456,-1.5257775,0.478125,-0.093122795,-2.0965574,1.621728,-0.86320823,-1.2825034, +0.4201416,0.5574868,0.7364114,-0.38600338,-0.010914338,-0.73080677,-1.3101974,1.0791306, +-0.102762684,-0.18231426,-1.9992676,-0.1783711,-0.8424945,-0.17461365,-0.21924415,-0.44646478, +0.93883866,0.44705415,1.1271545,-1.3248273,-0.64895594,-0.04028082,-0.40663898,-0.07925773, +-1.1821034,-0.71617806,-1.641554,-0.89002556,0.69417673,-0.21420689,1.5057533,-0.59553385, +0.11907108,-1.2132523,2.6006718,-0.17862059,0.82962984,0.41338503,-0.5838788,-1.3309013, +0.15614313,-0.55678976,-0.1555043,0.65130204,0.078241155,0.3771163,0.15004657,-1.4672493, +1.3960623,1.1758523,-1.1361649,0.50530064,-0.66202426,-0.74691635,-0.0048416615,1.7476683, +1.0579575,0.60522133,-1.1506057,2.5544493,0.873731,-2.3488374,0.39947432,-0.48869473, +0.40998235,0.40064037,-0.9185191,1.8258858,0.19978462,0.9413479,1.3514236,-0.7381576, +-0.9117685,1.1219074,1.3928374,-1.3770186,2.011243,-0.23550332,0.6917845,0.5643882, +-0.9713423,-0.8640481,-2.0835924,-1.1511501,-1.482476,0.040190514,1.3694022,-0.027144931, +0.33885416,0.7780035,0.67970943,-0.3858315,-1.463345,-0.42980552,0.06295936,-0.8716452, +0.3619607,-0.2927121,0.6218215,-0.80323946,-0.9219677,1.7740563,0.028756239,0.55296385, +-1.0984223,-0.37726447,0.6821695,1.5656159,-0.7244851,-0.8029174,-0.022668941,-1.5243951, +-0.030133307,-0.06472839,0.72474915,1.4146098,0.5698443,0.74155104,0.05227895,-0.35974458, +-1.9959769,-0.8862208,0.21726668,-1.6455938,0.24288982,-0.4008347,-1.0215598,-0.47002432, +0.7287815,0.8855011,-1.9370214,-0.14948401,0.91388464,-0.25789487,0.10881527,-1.4954109, +-0.48003367,1.8287754,-0.78806806,-1.4406323,0.14947176,0.78862935,1.1938105,-0.51772267, +0.22247557,0.54435486,0.6492105,-0.54720277,1.7127249,-0.68729705,0.70787215,-0.021911236, +-0.5872186,-0.6428513,-0.5863469,-0.44687107,-1.0188856,0.6974097,-0.7035153,-0.6150209, +0.48869058,-0.107961945,-1.4219036,-0.9360095,-0.19655724,-0.5749878,0.75048256,-0.76440203, +-0.9671271,-1.0105462,0.40665725,0.48347172,-1.6724446,0.6220752,0.8609733,-1.6909977, +-0.6904314,1.4288924,1.0061017,0.02479266,0.5012494,2.1120195,0.50279695,-1.2208089, +1.364939,-0.8709389,0.9939022,0.6562707,0.88951355,1.540933,-1.4659144,-0.06958856, +1.9460495,0.9763817,0.17715834,-1.0231731,0.10672049,-0.9118813,-1.468367,0.5764787, +0.065305606,-0.7735128,0.39494818,-0.50388986,1.7795591,-0.030572444,1.5770882,-0.8128021, +0.61334914,1.8436999,0.27109098,1.1364477,-1.7383319,0.7071347,0.030386131,0.76500195, +0.86766523,-2.2562501,-0.44360274,-0.67002326,0.15216419,-1.9405334,-1.0905087,1.0019207, +0.17689244,-1.0880145,-0.25321737,1.098273,-1.8395668,-0.21142861,-0.22966324,0.18697941, +0.5037795,1.9103425,0.5537812,-0.58748144,1.25795,-0.8586684,0.4361871,1.5714631, +1.0773149,0.8110897,-2.2315376,-0.101002514,-0.58737504,1.3248683,0.8406485,0.2611062, +0.79444164,-0.6496165,0.6342845,0.095002666,-1.6832068,0.34404615,0.707158,1.1934146, +0.5273885,1.006704,-1.7323273,-0.37341216,-0.1425104,-0.32974237,-0.08904212,-0.5773963, +0.73616546,-0.9912056,0.12517461,0.07315271,0.14393723,-0.94772434,1.3992299,-0.22612372, +-1.4388542,0.801301,-0.0033314459,-0.09694156,-0.09587145,0.39543697,-0.05324304,-0.7734996, +-1.4191855,0.30345193,-1.5182067,1.1197077,-0.95386094,-0.849614,-0.9818997,-1.3630776, +-0.77259856,-0.28362545,-2.327604,-2.4452274,-0.71586496,0.88339686,-1.3004398,-0.07633908, +1.4305568,-1.3234086,-0.43835616,-0.7431525,0.8919676,0.46387276,0.6176608,2.496417, +1.6294752,-0.0990447,-0.20199196,-1.4488258,-1.7141647,-0.049641572,-1.2993954,0.6253554, +-0.7917193,-0.5829434,-1.5526805,2.1101534,0.75882953,-0.70993024,0.15114704,1.3230913, +-0.9278251,1.9065987,-1.032175,-0.17736149,-1.6503783,-2.538511,1.0100908,0.08570209, +-1.733861,-1.6406012,1.1453614,-0.15059511,1.4314432,0.6365868,-0.06656285,0.03232998, +-0.5550736,0.097786106,-0.06098498,0.83751667,-0.16341844,0.82355547,0.9206323,0.1807626, +-1.3129684,-0.1604767,-1.9060746,-1.2066216,0.7304183,0.49489278,-0.0032088785,-0.30243316, +-0.7394009,-0.5128121,0.9652515,0.47667927,-1.3712165,0.19885284,0.13996284,1.6486734, +-1.7575518,-0.7831295,0.97362584,-1.1109322,2.3856215,-1.1789442,0.029122146,0.55954754, +0.8810371,0.7152085,-0.46207753,0.913207,-0.7546525,-0.53497714,0.45664245,1.5095769, +-0.22817124,-0.8903415,1.2097719,-1.2648001,1.8381815,-0.9840827,0.6409485,0.92669123, +0.78503406,0.22700264,0.049529552,-1.6531805,-0.78081965,0.72464466,0.6633692,-1.0378813, +0.34697902,0.252031,1.7509189,-0.41840115,-0.5198573,-0.92344296,-0.9992785,0.37494835, +-0.7043411,1.0747038,-0.6272991,1.5339956,0.41772544,0.25838363,-1.1504285,0.3291142, +0.04552198,0.6320826,-0.5108473,-1.4536299,0.2752216,0.13978724,0.24389236,1.0056502, +-0.93964064,-2.38175,0.475027,0.40591252,-0.4770563,0.17059821,-1.0477808,-2.106197, +-1.6929115,0.04236114,1.3827105,-0.38951838,0.8139379,-0.594332,-0.05543902,0.7965607, +0.13317989,-0.54167837,-0.8653024,-0.09252813,1.1821021,-1.5706546,0.8593308,0.283647, +-0.9691123,-0.01837373,-0.20403545,-0.9477404,-0.5394351,-1.2562873,-2.0715237,0.15123644, +1.0444895,1.6333491,-1.1113786,2.147365,1.5263067,1.423475,-0.7856664,-0.5622516, +-1.9383575,0.19115923,-0.39360294,0.16179068,-0.834518,0.67287046,0.3431881,-1.1441231, +-0.045887947,0.2846845,2.0084414,0.09578085,-0.940409,-0.31626305,-0.031223467,-0.13359529, +-1.8414719,-0.33157688,-0.6933089,-0.26051295,2.1209624,-0.8322906,1.437941,1.1606182, +0.68349785,0.0031104183,0.65439343,-0.4499198,-0.54645914,-0.7478617,0.27390158,-0.20977058, +-0.23958507,1.4202288,-0.7047485,0.7353649,-0.5219276,-1.592195,-1.4259504,-0.49155238 + +==== +name:CrossAttention_DiffSequenceLengths_UsingDMMHAInsideMHA.bias_data +0.6296115,0.6417864,-0.24068715,0.61842173,0.07626311,-0.26149032,0.85473126,1.1878939, +1.0160275,-0.30687296,0.5677076,-2.1292458,0.19506693,0.36100236,0.1519752,-0.22227272, +1.3047732,-0.0932377,-0.13953793,-0.24093674,1.0341054,-0.29245964,-0.8343494,-0.10875854, +1.7077137,-0.30068612,0.61577165,-0.27811074,-0.2767468,-0.5608414,-1.2163041,-0.10978163, +0.71845573,1.576193,0.4418695,-0.8168611,0.7455046,0.45402917,1.3983632,2.0896103, +1.2146077,-0.3927582,-0.15922955,1.1579405,-0.5076931,-0.14048347,0.6343402,1.0706061, +0.22291076,-2.8925197,0.33936596,-0.3120492,-0.975921,0.024130166,1.1204642,-1.1298772, +1.589923,0.9787301,0.93416363,-0.8147086,-0.25124246,-0.38283488,0.00034095792,-0.0622048, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 + +==== +name:CrossAttention_DiffSequenceLengths_UsingDMMHAInsideMHA.fp32_output_data +-0.6003144,0.5046919,-0.12049955,-0.92507327,-0.42686504,0.072453946,-0.5814661,0.5313442, +0.1532953,-0.656893,0.029914446,-0.47042838,-0.21011704,-0.112559795,0.16661634,0.109792024, +0.044871077,0.05542153,-0.32573918,0.19370267,-0.2627771,0.34857383,-0.08189575,-0.5832793, +-0.2708692,0.3207512,-0.12878786,0.7165755,-0.029289871,0.2647196,0.6524202,-0.82146287, +-0.3520299,-0.25118023,-0.038025014,0.78544146,0.09237215,0.79537904,-0.5381446,0.3168583, +-0.97991526,0.8569559,-0.055078603,0.16906464,0.14160854,0.41692847,-0.26472932,0.62255543, +-0.79614085,0.5630065,0.9804111,-0.22339875,-0.07803835,0.68520164,0.33540013,-0.5185654, +-0.5656776,0.75473773,0.5266086,0.5193186,0.4887605,-0.2469342,-0.33267665,-0.8284849, +-0.14604083,0.3660654,-0.15639517,-0.5218262,0.1303009,0.74157655,-0.044350415,0.081228435, +-1.144964,-0.25515392,0.41934747,-0.6562912,-0.5374121,0.057686627,-0.25775802,-0.6835696, +0.19294256,0.37835988,-0.059078366,-0.23943216,-0.078009665,0.0029286146,-0.20156968,-0.1876947, +-0.2378927,0.46250412,-0.3916942,-0.02140814,-0.19658206,-0.05838166,0.3902902,-0.7092172, +0.19089642,0.7120326,0.17214371,0.1678071,-0.41189647,0.44862992,-0.065859206,0.0844535, +-0.12370446,-0.5356797,-0.13798991,-0.0020032525,0.71459025,-0.1703992,-0.13581733,0.74633443, +0.43537667,0.30747345,-0.17322245,-0.2525632,-0.527473,-0.550586,-0.27879256,-0.31048977, +-0.54378724,-0.12629068,0.5371106,-0.15989208,0.6806373,-0.43645537,0.16498,-0.057793662 + +==== +name:CrossAttention_DiffSequenceLengths_UsingDMMHAInsideMHA.fp32_output_qk_data +-1.2014943,0.6843257,-0.6116703,-0.5371384,0.66629004,0.033044804,0.9717946,0.15667602, +0.6141628,0.16917382,-0.566475,1.8491349,-0.024795728,1.3970505,-0.019675655,3.1860712, +-2.741984,1.6077112,-0.07165447,-0.03905407,-1.2188541,-0.5628502,0.09844631,1.32231, +1.332324,0.58346725,-0.86279655,1.3619442,1.4080318,-1.0267601,1.0768844,-0.0887926, +0.028943084,-1.9949476,0.7381273,-1.2816228,0.25567636,0.59148777,-0.11591597,0.7770739 diff --git a/onnxruntime/test/testdata/cast_float_to_double.onnx b/onnxruntime/test/testdata/cast_float_to_double.onnx new file mode 100644 index 0000000000000..dc7997cddd8a8 Binary files /dev/null and b/onnxruntime/test/testdata/cast_float_to_double.onnx differ diff --git a/onnxruntime/test/testdata/custom_execution_provider_library/my_execution_provider.cc b/onnxruntime/test/testdata/custom_execution_provider_library/my_execution_provider.cc index 57471f7c029c2..27a4b06a99e64 100644 --- a/onnxruntime/test/testdata/custom_execution_provider_library/my_execution_provider.cc +++ b/onnxruntime/test/testdata/custom_execution_provider_library/my_execution_provider.cc @@ -1,5 +1,5 @@ // Copyright (c) Microsoft Corporation. All rights reserved. -// Confidential and Proprietary. +// Licensed under the MIT License. #include "my_execution_provider.h" #include "my_allocator.h" diff --git a/onnxruntime/test/testdata/custom_execution_provider_library/my_execution_provider.h b/onnxruntime/test/testdata/custom_execution_provider_library/my_execution_provider.h index ff0c7e80c4eeb..efb359a9e5e43 100644 --- a/onnxruntime/test/testdata/custom_execution_provider_library/my_execution_provider.h +++ b/onnxruntime/test/testdata/custom_execution_provider_library/my_execution_provider.h @@ -1,5 +1,5 @@ // Copyright (c) Microsoft Corporation. All rights reserved. -// Confidential and Proprietary. +// Licensed under the MIT License. #pragma once diff --git a/onnxruntime/test/testdata/dmmha_cross_attn.onnx b/onnxruntime/test/testdata/dmmha_cross_attn.onnx new file mode 100644 index 0000000000000..2717d129448e1 Binary files /dev/null and b/onnxruntime/test/testdata/dmmha_cross_attn.onnx differ diff --git a/onnxruntime/test/testdata/dmmha_inside_mha_cross_attn.onnx b/onnxruntime/test/testdata/dmmha_inside_mha_cross_attn.onnx new file mode 100644 index 0000000000000..e04a317cd640c Binary files /dev/null and b/onnxruntime/test/testdata/dmmha_inside_mha_cross_attn.onnx differ diff --git a/onnxruntime/test/testdata/dmmha_inside_mha_data.py b/onnxruntime/test/testdata/dmmha_inside_mha_data.py new file mode 100644 index 0000000000000..a7edbaf0d34ab --- /dev/null +++ b/onnxruntime/test/testdata/dmmha_inside_mha_data.py @@ -0,0 +1,195 @@ +import numpy as np + +import onnxruntime as ort +from onnxruntime import OrtValue + +np.random.seed(0) + + +# Whisper decoder self attention with past_kv, present_kv, buffer sharing enabled, mask, and bias +# Used in decoder-with-past's self-attention layers +# For CUDA, K caches are transposed and reshaped from 4D to 5D for DecoderMaskedMultiHeadAttention +# See onnxruntime/core/graph/contrib_ops/bert_defs.cc for more details +def dmmha_inside_mha_self_attn(): + batch_size, num_heads, head_size = 2, 2, 32 + hidden_size = num_heads * head_size + past_sequence_length, sequence_length, max_sequence_length = 4, 1, 6 + num_beams = 1 + device = "cuda" + + inputs = { + "q": np.random.randn(batch_size, sequence_length, hidden_size).astype(np.float32), + "k": np.random.randn(batch_size, sequence_length, hidden_size).astype(np.float32), + "v": np.random.randn(batch_size, sequence_length, hidden_size).astype(np.float32), + "b": np.random.randn(hidden_size * 3).astype(np.float32), + "past_k": np.zeros((batch_size, num_heads, max_sequence_length, head_size)).astype(np.float32), + "past_v": np.zeros((batch_size, num_heads, max_sequence_length, head_size)).astype(np.float32), + "past_seq_len": np.array([past_sequence_length]).astype(np.int32), + "cache_indir": np.zeros((batch_size, num_beams, max_sequence_length)).astype(np.int32), + } + inputs["past_k"][:batch_size, :num_heads, :past_sequence_length, :head_size] = np.random.randn( + batch_size, num_heads, past_sequence_length, head_size + ).astype(np.float32) + inputs["past_v"][:batch_size, :num_heads, :past_sequence_length, :head_size] = np.random.randn( + batch_size, num_heads, past_sequence_length, head_size + ).astype(np.float32) + print_vals(inputs) + + sess = ort.InferenceSession("dmmha_inside_mha_self_attn.onnx", providers=[f"{device.upper()}ExecutionProvider"]) + io_binding = sess.io_binding() + past_k_ortvalue, past_v_ortvalue = None, None + for k, v in inputs.items(): + v_device = OrtValue.ortvalue_from_numpy(v, device_type=device.lower(), device_id=0) + io_binding.bind_ortvalue_input(k, v_device) + if k == "past_k": + past_k_ortvalue = v_device + elif k == "past_v": + past_v_ortvalue = v_device + for output in sess.get_outputs(): + name = output.name + if name == "present_k": + io_binding.bind_ortvalue_output(name, past_k_ortvalue) + elif name == "present_v": + io_binding.bind_ortvalue_output(name, past_v_ortvalue) + else: + io_binding.bind_output(name, device_type=device.lower(), device_id=0) + + sess.run_with_iobinding(io_binding) + outputs = io_binding.copy_outputs_to_cpu() + + print_vals(outputs) + + +# Whisper decoder self attention with past_kv, present_kv, buffer sharing enabled, mask, and bias +# Used in decoder-with-past's self-attention layers +# For CUDA, K caches are transposed and reshaped from 4D to 5D for DecoderMaskedMultiHeadAttention +# See onnxruntime/core/graph/contrib_ops/bert_defs.cc for more details +def dmmha_self_attn(): + batch_size, num_heads, head_size = 2, 2, 32 + hidden_size = num_heads * head_size + past_sequence_length, sequence_length, max_sequence_length = 4, 1, 6 + num_beams = 1 + device = "cuda" + + inputs = { + "q": np.random.randn(batch_size, sequence_length, hidden_size).astype(np.float32), + "k": np.random.randn(batch_size, sequence_length, hidden_size).astype(np.float32), + "v": np.random.randn(batch_size, sequence_length, hidden_size).astype(np.float32), + "b": np.random.randn(hidden_size * 3).astype(np.float32), + "past_k": np.zeros((batch_size, num_heads, max_sequence_length, head_size)).astype(np.float32), + "past_v": np.zeros((batch_size, num_heads, max_sequence_length, head_size)).astype(np.float32), + "past_seq_len": np.array([past_sequence_length]).astype(np.int32), + "beam_width": np.array([num_beams]).astype(np.int32), + "cache_indir": np.zeros((batch_size, num_beams, max_sequence_length)).astype(np.int32), + } + inputs["past_k"][:batch_size, :num_heads, :past_sequence_length, :head_size] = np.random.randn( + batch_size, num_heads, past_sequence_length, head_size + ).astype(np.float32) + inputs["past_v"][:batch_size, :num_heads, :past_sequence_length, :head_size] = np.random.randn( + batch_size, num_heads, past_sequence_length, head_size + ).astype(np.float32) + print_vals(inputs) + + sess = ort.InferenceSession("dmmha_self_attn.onnx", providers=[f"{device.upper()}ExecutionProvider"]) + io_binding = sess.io_binding() + past_k_ortvalue, past_v_ortvalue = None, None + for k, v in inputs.items(): + v_device = OrtValue.ortvalue_from_numpy(v, device_type=device.lower(), device_id=0) + io_binding.bind_ortvalue_input(k, v_device) + if k == "past_k": + past_k_ortvalue = v_device + elif k == "past_v": + past_v_ortvalue = v_device + for output in sess.get_outputs(): + name = output.name + if name == "present_k": + io_binding.bind_ortvalue_output(name, past_k_ortvalue) + elif name == "present_v": + io_binding.bind_ortvalue_output(name, past_v_ortvalue) + else: + io_binding.bind_output(name, device_type=device.lower(), device_id=0) + + sess.run_with_iobinding(io_binding) + outputs = io_binding.copy_outputs_to_cpu() + + print_vals(outputs) + + +# Whisper decoder cross attention with past_kv used directly as K and V, no mask, and bias +# Used in decoder-with-past's cross-attention layers +def dmmha_inside_mha_cross_attn(): + batch_size, num_heads, head_size = 2, 2, 32 + hidden_size = num_heads * head_size + past_sequence_length, sequence_length, kv_sequence_length, max_sequence_length = 4, 1, 10, 6 + num_beams = 1 + device = "cuda" + + inputs = { + "q": np.random.randn(batch_size, sequence_length, hidden_size).astype(np.float32), + "k": np.random.randn(batch_size, num_heads, kv_sequence_length, head_size).astype(np.float32), + "v": np.random.randn(batch_size, num_heads, kv_sequence_length, head_size).astype(np.float32), + "b": np.zeros(hidden_size * 3).astype(np.float32), + "past_seq_len": np.array([past_sequence_length]).astype(np.int32), + "cache_indir": np.zeros((batch_size, num_beams, max_sequence_length)).astype(np.int32), + } + inputs["b"][:hidden_size] = np.random.randn(hidden_size).astype(np.float32) + print_vals(inputs) + + sess = ort.InferenceSession("dmmha_inside_mha_cross_attn.onnx", providers=[f"{device.upper()}ExecutionProvider"]) + outputs = sess.run(None, inputs) + + print_vals(outputs) + + +# Whisper decoder cross attention with past_kv used directly as K and V, no mask, and bias +# Used in decoder-with-past's cross-attention layers +def dmmha_cross_attn(): + batch_size, num_heads, head_size = 2, 2, 32 + hidden_size = num_heads * head_size + past_sequence_length, sequence_length, kv_sequence_length, max_sequence_length = 4, 1, 10, 6 + num_beams = 1 + device = "cuda" + + inputs = { + "q": np.random.randn(batch_size, sequence_length, hidden_size).astype(np.float32), + "k": np.random.randn(batch_size, num_heads, kv_sequence_length, head_size).astype(np.float32), + "v": np.random.randn(batch_size, num_heads, kv_sequence_length, head_size).astype(np.float32), + "b": np.zeros(hidden_size * 3).astype(np.float32), + "past_seq_len": np.array([past_sequence_length]).astype(np.int32), + "beam_width": np.array([num_beams]).astype(np.int32), + "cache_indir": np.zeros((batch_size, num_beams, max_sequence_length)).astype(np.int32), + } + inputs["b"][:hidden_size] = np.random.randn(hidden_size).astype(np.float32) + print_vals(inputs) + + sess = ort.InferenceSession("dmmha_cross_attn.onnx", providers=[f"{device.upper()}ExecutionProvider"]) + outputs = sess.run(None, inputs) + + print_vals(outputs) + + +# Print values in format for onnxruntime/test/testdata/attention/attention_test_data.txt +def print_vals(L): + if isinstance(L, list): + for idx, elm in enumerate(L): + print(f"\nOutput {idx}:", flush=True) + for i, entry in enumerate(elm.flatten()): + print(entry, end=",", flush=True) + if i % 8 == 0 and i != 0: + print("\n", end="", flush=True) + elif isinstance(L, dict): + for key, val in L.items(): + print(f"\n{key}:", flush=True) + for i, entry in enumerate(val.flatten()): + print(entry, end=",", flush=True) + if i % 8 == 0 and i != 0: + print("\n", end="", flush=True) + + print("\n=====================================================", flush=True) + + +dmmha_inside_mha_self_attn() +dmmha_inside_mha_cross_attn() + +dmmha_self_attn() +dmmha_cross_attn() diff --git a/onnxruntime/test/testdata/dmmha_inside_mha_graph.py b/onnxruntime/test/testdata/dmmha_inside_mha_graph.py new file mode 100644 index 0000000000000..c019afe9a6c17 --- /dev/null +++ b/onnxruntime/test/testdata/dmmha_inside_mha_graph.py @@ -0,0 +1,235 @@ +from onnx import TensorProto, helper, save_model + + +# Whisper decoder self attention with past_kv, present_kv, buffer sharing enabled, mask, and bias +# Used in decoder-with-past's self-attention layers +def dmmha_inside_mha_self_attn(): + num_heads, head_size = 2, 32 + hidden_size = num_heads * head_size + + # Inputs + q = helper.make_tensor_value_info("q", TensorProto.FLOAT, ["batch_size", "sequence_length", hidden_size]) + k = helper.make_tensor_value_info("k", TensorProto.FLOAT, ["batch_size", "sequence_length", hidden_size]) + v = helper.make_tensor_value_info("v", TensorProto.FLOAT, ["batch_size", "sequence_length", hidden_size]) + b = helper.make_tensor_value_info("b", TensorProto.FLOAT, [hidden_size * 3]) + past_k = helper.make_tensor_value_info( + "past_k", TensorProto.FLOAT, ["batch_size", num_heads, "max_sequence_length", head_size] + ) + past_v = helper.make_tensor_value_info( + "past_v", TensorProto.FLOAT, ["batch_size", num_heads, "max_sequence_length", head_size] + ) + past_seq_len = helper.make_tensor_value_info("past_seq_len", TensorProto.INT32, [1]) + cache_indir = helper.make_tensor_value_info( + "cache_indir", TensorProto.INT32, ["batch_size", "num_beams", "max_sequence_length"] + ) + inputs = [q, k, v, b, past_k, past_v, past_seq_len, cache_indir] + + # Outputs + o = helper.make_tensor_value_info("o", TensorProto.FLOAT, ["batch_size", "sequence_length", hidden_size]) + present_k = helper.make_tensor_value_info( + "present_k", TensorProto.FLOAT, ["batch_size", num_heads, "max_sequence_length", head_size] + ) + present_v = helper.make_tensor_value_info( + "present_v", TensorProto.FLOAT, ["batch_size", num_heads, "max_sequence_length", head_size] + ) + outputs = [o, present_k, present_v] + + model = helper.make_model( + helper.make_graph( + [ + helper.make_node( + "MultiHeadAttention", + inputs=["q", "k", "v", "b", "", "", "past_k", "past_v", "past_seq_len", "cache_indir"], + outputs=["o", "present_k", "present_v"], + name="MultiHeadAttention", + domain="com.microsoft", + num_heads=num_heads, + unidirectional=1, + ) + ], + "dmmha-inside-mha-self-attn-graph", + inputs, + outputs, + ), + opset_imports=[helper.make_opsetid("", 17)], + ) + save_model(model, "dmmha_inside_mha_self_attn.onnx") + + +# Whisper decoder self attention with past_kv, present_kv, buffer sharing enabled, mask, and bias +# Used in decoder-with-past's self-attention layers +def dmmha_self_attn(): + num_heads, head_size = 2, 32 + hidden_size = num_heads * head_size + + # Inputs + q = helper.make_tensor_value_info("q", TensorProto.FLOAT, ["batch_size", "sequence_length", hidden_size]) + k = helper.make_tensor_value_info("k", TensorProto.FLOAT, ["batch_size", "sequence_length", hidden_size]) + v = helper.make_tensor_value_info("v", TensorProto.FLOAT, ["batch_size", "sequence_length", hidden_size]) + b = helper.make_tensor_value_info("b", TensorProto.FLOAT, [hidden_size * 3]) + past_k = helper.make_tensor_value_info( + "past_k", TensorProto.FLOAT, ["batch_size", num_heads, "max_sequence_length", head_size] + ) + past_v = helper.make_tensor_value_info( + "past_v", TensorProto.FLOAT, ["batch_size", num_heads, "max_sequence_length", head_size] + ) + past_seq_len = helper.make_tensor_value_info("past_seq_len", TensorProto.INT32, [1]) + beam_width = helper.make_tensor_value_info("beam_width", TensorProto.INT32, [1]) + cache_indir = helper.make_tensor_value_info( + "cache_indir", TensorProto.INT32, ["batch_size", "num_beams", "max_sequence_length"] + ) + inputs = [q, k, v, b, past_k, past_v, past_seq_len, beam_width, cache_indir] + + # Outputs + o = helper.make_tensor_value_info("o", TensorProto.FLOAT, ["batch_size", "sequence_length", hidden_size]) + present_k = helper.make_tensor_value_info( + "present_k", TensorProto.FLOAT, ["batch_size", num_heads, "max_sequence_length", head_size] + ) + present_v = helper.make_tensor_value_info( + "present_v", TensorProto.FLOAT, ["batch_size", num_heads, "max_sequence_length", head_size] + ) + outputs = [o, present_k, present_v] + + model = helper.make_model( + helper.make_graph( + [ + helper.make_node( + "DecoderMaskedMultiHeadAttention", + inputs=[ + "q", + "k", + "v", + "", + "", + "past_k", + "past_v", + "past_seq_len", + "beam_width", + "cache_indir", + "b", + ], + outputs=["o", "present_k", "present_v"], + name="DecoderMaskedMultiHeadAttention", + domain="com.microsoft", + num_heads=num_heads, + past_present_share_buffer=1, + ) + ], + "dmmha-self-attn-graph", + inputs, + outputs, + ), + opset_imports=[helper.make_opsetid("", 17)], + ) + save_model(model, "dmmha_self_attn.onnx") + + +# Whisper decoder cross attention with past_kv used directly as K and V, no mask, and bias +# Used in decoder-with-past's cross-attention layers +def dmmha_inside_mha_cross_attn(): + num_heads, head_size = 2, 32 + hidden_size = num_heads * head_size + encoder_seq_len = 10 + + # Inputs + q = helper.make_tensor_value_info("q", TensorProto.FLOAT, ["batch_size", "sequence_length", hidden_size]) + past_k = helper.make_tensor_value_info( + "k", TensorProto.FLOAT, ["batch_size", num_heads, encoder_seq_len, head_size] + ) + past_v = helper.make_tensor_value_info( + "v", TensorProto.FLOAT, ["batch_size", num_heads, encoder_seq_len, head_size] + ) + b = helper.make_tensor_value_info("b", TensorProto.FLOAT, [hidden_size * 3]) + past_seq_len = helper.make_tensor_value_info("past_seq_len", TensorProto.INT32, [1]) + cache_indir = helper.make_tensor_value_info( + "cache_indir", TensorProto.INT32, ["batch_size", "num_beams", "max_sequence_length"] + ) + inputs = [q, past_k, past_v, b, past_seq_len, cache_indir] + + # Outputs + o = helper.make_tensor_value_info("o", TensorProto.FLOAT, ["batch_size", "sequence_length", hidden_size]) + qk = helper.make_tensor_value_info( + "qk", TensorProto.FLOAT, ["batch_size", "num_heads", "sequence_length", "total_sequence_length"] + ) + outputs = [o, qk] + + model = helper.make_model( + helper.make_graph( + [ + helper.make_node( + "MultiHeadAttention", + inputs=["q", "k", "v", "b", "", "", "", "", "past_seq_len", "cache_indir"], + outputs=["o", "", "", "qk"], + name="MultiHeadAttention", + domain="com.microsoft", + num_heads=num_heads, + unidirectional=0, + ) + ], + "dmmha-inside-mha-cross-attn-graph", + inputs, + outputs, + ), + opset_imports=[helper.make_opsetid("", 17)], + ) + save_model(model, "dmmha_inside_mha_cross_attn.onnx") + + +# Whisper decoder cross attention with past_kv used directly as K and V, no mask, and bias +# Used in decoder-with-past's cross-attention layers +def dmmha_cross_attn(): + num_heads, head_size = 2, 32 + hidden_size = num_heads * head_size + encoder_seq_len = 10 + + # Inputs + q = helper.make_tensor_value_info("q", TensorProto.FLOAT, ["batch_size", "sequence_length", hidden_size]) + past_k = helper.make_tensor_value_info( + "k", TensorProto.FLOAT, ["batch_size", num_heads, encoder_seq_len, head_size] + ) + past_v = helper.make_tensor_value_info( + "v", TensorProto.FLOAT, ["batch_size", num_heads, encoder_seq_len, head_size] + ) + b = helper.make_tensor_value_info("b", TensorProto.FLOAT, [hidden_size * 3]) + past_seq_len = helper.make_tensor_value_info("past_seq_len", TensorProto.INT32, [1]) + beam_width = helper.make_tensor_value_info("beam_width", TensorProto.INT32, [1]) + cache_indir = helper.make_tensor_value_info( + "cache_indir", TensorProto.INT32, ["batch_size", "num_beams", "max_sequence_length"] + ) + inputs = [q, past_k, past_v, b, past_seq_len, beam_width, cache_indir] + + # Outputs + o = helper.make_tensor_value_info("o", TensorProto.FLOAT, ["batch_size", "sequence_length", hidden_size]) + qk = helper.make_tensor_value_info( + "qk", TensorProto.FLOAT, ["batch_size", "num_heads", "sequence_length", "total_sequence_length"] + ) + outputs = [o, qk] + + model = helper.make_model( + helper.make_graph( + [ + helper.make_node( + "DecoderMaskedMultiHeadAttention", + inputs=["q", "k", "v", "", "", "", "", "past_seq_len", "beam_width", "cache_indir", "b"], + outputs=["o", "", "", "qk"], + name="DecoderMaskedMultiHeadAttention", + domain="com.microsoft", + num_heads=num_heads, + output_qk=1, + past_present_share_buffer=0, + ) + ], + "dmmha-cross-attn-graph", + inputs, + outputs, + ), + opset_imports=[helper.make_opsetid("", 17)], + ) + save_model(model, "dmmha_cross_attn.onnx") + + +dmmha_inside_mha_self_attn() +dmmha_inside_mha_cross_attn() + +dmmha_self_attn() +dmmha_cross_attn() diff --git a/onnxruntime/test/testdata/dmmha_inside_mha_self_attn.onnx b/onnxruntime/test/testdata/dmmha_inside_mha_self_attn.onnx new file mode 100644 index 0000000000000..959910677225d Binary files /dev/null and b/onnxruntime/test/testdata/dmmha_inside_mha_self_attn.onnx differ diff --git a/onnxruntime/test/testdata/dmmha_self_attn.onnx b/onnxruntime/test/testdata/dmmha_self_attn.onnx new file mode 100644 index 0000000000000..bcf369e0faea9 Binary files /dev/null and b/onnxruntime/test/testdata/dmmha_self_attn.onnx differ diff --git a/onnxruntime/test/testdata/gh_issue_24203.onnx b/onnxruntime/test/testdata/gh_issue_24203.onnx new file mode 100644 index 0000000000000..535b79f65cf70 Binary files /dev/null and b/onnxruntime/test/testdata/gh_issue_24203.onnx differ diff --git a/onnxruntime/test/testdata/onnx_backend_test_series_filters.jsonc b/onnxruntime/test/testdata/onnx_backend_test_series_filters.jsonc index e261d66a0d22a..d62ffe644e4cc 100644 --- a/onnxruntime/test/testdata/onnx_backend_test_series_filters.jsonc +++ b/onnxruntime/test/testdata/onnx_backend_test_series_filters.jsonc @@ -694,7 +694,9 @@ "^test_gelu_tanh_2_expanded_cpu", "^test_dynamicquantizelinear_expanded_cpu", "^test_center_crop_pad_crop_negative_axes_hwc*", // failed due to new types or shape infer with negative axis for CenterCropPad. - "^test_center_crop_pad_crop_negative_axes_hwc_expanded*" // failed due to new types or shape infer with negative axis for CenterCropPad. + "^test_center_crop_pad_crop_negative_axes_hwc_expanded*", // failed due to new types or shape infer with negative axis for CenterCropPad. + "^test_reduce_max_empty_set", + "^test_reduce_min_empty_set" ], "current_failing_tests_pure_DML": [ "^test_negative_log_likelihood_loss_input_shape_is_NCd1d2d3_none_no_weight_negative_ignore_index_cpu", diff --git a/onnxruntime/test/testdata/transformers/tiny_t5/added_tokens.json b/onnxruntime/test/testdata/transformers/tiny_t5/added_tokens.json new file mode 100644 index 0000000000000..3f5132007c4fc --- /dev/null +++ b/onnxruntime/test/testdata/transformers/tiny_t5/added_tokens.json @@ -0,0 +1,102 @@ +{ + "": 32099, + "": 32089, + "": 32088, + "": 32087, + "": 32086, + "": 32085, + "": 32084, + "": 32083, + "": 32082, + "": 32081, + "": 32080, + "": 32098, + "": 32079, + "": 32078, + "": 32077, + "": 32076, + "": 32075, + "": 32074, + "": 32073, + "": 32072, + "": 32071, + "": 32070, + "": 32097, + "": 32069, + "": 32068, + "": 32067, + "": 32066, + "": 32065, + "": 32064, + "": 32063, + "": 32062, + "": 32061, + "": 32060, + "": 32096, + "": 32059, + "": 32058, + "": 32057, + "": 32056, + "": 32055, + "": 32054, + "": 32053, + "": 32052, + "": 32051, + "": 32050, + "": 32095, + "": 32049, + "": 32048, + "": 32047, + "": 32046, + "": 32045, + "": 32044, + "": 32043, + "": 32042, + "": 32041, + "": 32040, + "": 32094, + "": 32039, + "": 32038, + "": 32037, + "": 32036, + "": 32035, + "": 32034, + "": 32033, + "": 32032, + "": 32031, + "": 32030, + "": 32093, + "": 32029, + "": 32028, + "": 32027, + "": 32026, + "": 32025, + "": 32024, + "": 32023, + "": 32022, + "": 32021, + "": 32020, + "": 32092, + "": 32019, + "": 32018, + "": 32017, + "": 32016, + "": 32015, + "": 32014, + "": 32013, + "": 32012, + "": 32011, + "": 32010, + "": 32091, + "": 32009, + "": 32008, + "": 32007, + "": 32006, + "": 32005, + "": 32004, + "": 32003, + "": 32002, + "": 32001, + "": 32000, + "": 32090 +} diff --git a/onnxruntime/test/testdata/transformers/tiny_t5/config.json b/onnxruntime/test/testdata/transformers/tiny_t5/config.json new file mode 100644 index 0000000000000..d649732da246f --- /dev/null +++ b/onnxruntime/test/testdata/transformers/tiny_t5/config.json @@ -0,0 +1,60 @@ +{ + "architectures": [ + "T5ForConditionalGeneration" + ], + "classifier_dropout": 0.0, + "d_ff": 16, + "d_kv": 4, + "d_model": 8, + "decoder_start_token_id": 0, + "dense_act_fn": "relu", + "dropout_rate": 0.1, + "eos_token_id": 1, + "feed_forward_proj": "relu", + "initializer_factor": 1.0, + "is_encoder_decoder": true, + "is_gated_act": false, + "layer_norm_epsilon": 1e-06, + "model_type": "t5", + "n_positions": 512, + "num_decoder_layers": 2, + "num_heads": 2, + "num_layers": 2, + "output_past": true, + "pad_token_id": 0, + "relative_attention_max_distance": 128, + "relative_attention_num_buckets": 32, + "task_specific_params": { + "summarization": { + "early_stopping": true, + "length_penalty": 2.0, + "max_length": 200, + "min_length": 30, + "no_repeat_ngram_size": 3, + "num_beams": 4, + "prefix": "summarize: " + }, + "translation_en_to_de": { + "early_stopping": true, + "max_length": 300, + "num_beams": 4, + "prefix": "translate English to German: " + }, + "translation_en_to_fr": { + "early_stopping": true, + "max_length": 300, + "num_beams": 4, + "prefix": "translate English to French: " + }, + "translation_en_to_ro": { + "early_stopping": true, + "max_length": 300, + "num_beams": 4, + "prefix": "translate English to Romanian: " + } + }, + "torch_dtype": "float32", + "transformers_version": "4.42.4", + "use_cache": true, + "vocab_size": 1024 +} diff --git a/onnxruntime/test/testdata/transformers/tiny_t5/generation_config.json b/onnxruntime/test/testdata/transformers/tiny_t5/generation_config.json new file mode 100644 index 0000000000000..6f2a63c77c1b9 --- /dev/null +++ b/onnxruntime/test/testdata/transformers/tiny_t5/generation_config.json @@ -0,0 +1,7 @@ +{ + "_from_model_config": true, + "decoder_start_token_id": 0, + "eos_token_id": 1, + "pad_token_id": 0, + "transformers_version": "4.42.4" +} diff --git a/onnxruntime/test/testdata/transformers/tiny_t5/model.safetensors b/onnxruntime/test/testdata/transformers/tiny_t5/model.safetensors new file mode 100644 index 0000000000000..1b90602ed0709 Binary files /dev/null and b/onnxruntime/test/testdata/transformers/tiny_t5/model.safetensors differ diff --git a/onnxruntime/test/testdata/transformers/tiny_t5/special_tokens_map.json b/onnxruntime/test/testdata/transformers/tiny_t5/special_tokens_map.json new file mode 100644 index 0000000000000..17ade346a1042 --- /dev/null +++ b/onnxruntime/test/testdata/transformers/tiny_t5/special_tokens_map.json @@ -0,0 +1,125 @@ +{ + "additional_special_tokens": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "eos_token": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false + }, + "pad_token": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false + }, + "unk_token": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false + } +} diff --git a/onnxruntime/test/testdata/transformers/tiny_t5/spiece.model b/onnxruntime/test/testdata/transformers/tiny_t5/spiece.model new file mode 100644 index 0000000000000..16ff05c4dd0f9 Binary files /dev/null and b/onnxruntime/test/testdata/transformers/tiny_t5/spiece.model differ diff --git a/onnxruntime/test/testdata/transformers/tiny_t5/tiny_t5.py b/onnxruntime/test/testdata/transformers/tiny_t5/tiny_t5.py new file mode 100644 index 0000000000000..6a25cb89f6327 --- /dev/null +++ b/onnxruntime/test/testdata/transformers/tiny_t5/tiny_t5.py @@ -0,0 +1,85 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +import os + +from sentencepiece import SentencePieceProcessor, SentencePieceTrainer +from transformers import T5Config, T5ForConditionalGeneration, T5Tokenizer + +hidden_size = 8 + +vocab_size = 1024 +save_directory = "tiny_t5" +model_name = "google-t5/t5-small" + +config = T5Config.from_pretrained(model_name) + +config.num_heads = 2 + +if vocab_size: + config.vocab_size = 1024 + +config.d_model = hidden_size +config.d_kv = hidden_size // config.num_heads +config.d_ff = hidden_size * 2 +config.num_layers = 2 +config.num_decoder_layers = config.num_layers + +model = T5ForConditionalGeneration(config) + +model.save_pretrained(save_directory) + +tokenizer = T5Tokenizer.from_pretrained(model_name, legacy=False) +tokenizer.save_pretrained(save_directory) + + +def update_tokenizer(sp_model_path: str, vocab_size: int): + sp = SentencePieceProcessor() + sp.Load(sp_model_path) + + # Export the vocabulary + with open("vocab.txt", "w", encoding="utf-8") as f: + for id in range(sp.GetPieceSize()): + piece = sp.IdToPiece(id) + score = sp.GetScore(id) + f.write(f"{piece}\t{score}\n") + + with open("vocab.txt", encoding="utf-8") as f: + vocab = [line.strip().split("\t") for line in f] + + # Sort by score in descending order and select top tokens + vocab_sorted = sorted(vocab, key=lambda x: float(x[1]), reverse=True) + pruned_vocab = vocab_sorted[:vocab_size] + + # Write the pruned vocabulary to a new file + with open("pruned_vocab.txt", "w", encoding="utf-8") as f: + for piece, score in pruned_vocab: + f.write(f"{piece}\t{score}\n") + + # Train a new SentencePiece model using the pruned vocabulary as a seed. + # Example corpus.txt can be found by searching "corpus.txt download" in search engine. + SentencePieceTrainer.Train( + f"--input=corpus.txt --model_prefix=spiece --vocab_size={vocab_size} --user_defined_symbols=pruned_vocab.txt" + ) + + # Load the new model + sp_new = SentencePieceProcessor() + sp_new.Load("spiece.model") + + # Test encoding and decoding + text = "This is an example sentence." + tokens = sp_new.EncodeAsPieces(text) + print(tokens) + + detokenized_text = sp_new.DecodePieces(tokens) + print(detokenized_text) + + # Replace the original model. + os.replace("spiece.model", sp_model_path) + + +if vocab_size: + original_path = os.path.join(save_directory, "spiece.model") + update_tokenizer(original_path, vocab_size) diff --git a/onnxruntime/test/testdata/transformers/tiny_t5/tokenizer_config.json b/onnxruntime/test/testdata/transformers/tiny_t5/tokenizer_config.json new file mode 100644 index 0000000000000..da3a2f5a033d6 --- /dev/null +++ b/onnxruntime/test/testdata/transformers/tiny_t5/tokenizer_config.json @@ -0,0 +1,940 @@ +{ + "add_prefix_space": true, + "added_tokens_decoder": { + "0": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "1": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "2": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32000": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32001": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32002": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32003": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32004": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32005": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32006": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32007": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32008": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32009": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32010": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32011": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32012": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32013": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32014": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32015": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32016": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32017": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32018": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32019": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32020": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32021": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32022": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32023": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32024": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32025": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32026": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32027": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32028": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32029": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32030": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32031": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32032": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32033": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32034": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32035": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32036": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32037": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32038": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32039": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32040": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32041": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32042": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32043": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32044": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32045": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32046": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32047": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32048": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32049": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32050": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32051": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32052": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32053": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32054": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32055": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32056": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32057": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32058": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32059": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32060": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32061": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32062": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32063": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32064": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32065": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32066": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32067": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32068": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32069": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32070": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32071": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32072": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32073": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32074": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32075": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32076": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32077": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32078": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32079": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32080": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32081": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32082": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32083": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32084": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32085": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32086": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32087": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32088": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32089": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32090": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32091": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32092": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32093": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32094": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32095": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32096": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32097": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32098": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32099": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + } + }, + "additional_special_tokens": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "clean_up_tokenization_spaces": true, + "eos_token": "", + "extra_ids": 100, + "legacy": false, + "model_max_length": 512, + "pad_token": "", + "sp_model_kwargs": {}, + "tokenizer_class": "T5Tokenizer", + "unk_token": "" +} diff --git a/onnxruntime/test/unittest_main/test_main.cc b/onnxruntime/test/unittest_main/test_main.cc index b558a7f00f7bc..56c11039328bc 100644 --- a/onnxruntime/test/unittest_main/test_main.cc +++ b/onnxruntime/test/unittest_main/test_main.cc @@ -5,6 +5,10 @@ #include #include #include +#ifdef _WIN32 +#include +#include +#endif #ifndef USE_ONNXRUNTIME_DLL #ifdef __GNUC__ @@ -29,6 +33,11 @@ std::unique_ptr ort_env; // ortenv_setup() and ortenv_teardown() are used by onnxruntime/test/xctest/xcgtest.mm so can't be file local extern "C" void ortenv_setup() { +#ifdef _WIN32 + // Set the locale to UTF-8 to ensure proper handling of wide characters on Windows + std::wclog.imbue(std::locale(".UTF-8", std::locale::ctype)); +#endif + OrtThreadingOptions tpo; // allow verbose logging to be enabled by setting this environment variable to a numeric log level diff --git a/onnxruntime/wasm/api.cc b/onnxruntime/wasm/api.cc index 7adfc6a2b2ccb..147eab7116d94 100644 --- a/onnxruntime/wasm/api.cc +++ b/onnxruntime/wasm/api.cc @@ -8,6 +8,14 @@ #include "core/session/onnxruntime_cxx_api.h" #include "api.h" +#ifdef USE_WEBGPU +namespace onnxruntime { +namespace webgpu { +WGPUDevice GetDevice(int); +} +} // namespace onnxruntime +#endif + #include #include #include @@ -164,8 +172,12 @@ OrtSessionOptions* OrtCreateSessionOptions(size_t graph_optimization_level, return UNREGISTER_AUTO_RELEASE(session_options); } -int OrtAppendExecutionProvider(ort_session_options_handle_t session_options, const char* name) { - return CHECK_STATUS(SessionOptionsAppendExecutionProvider, session_options, name, nullptr, nullptr, 0); +int OrtAppendExecutionProvider(ort_session_options_handle_t session_options, + const char* name, + const char* const* provider_options_keys, + const char* const* provider_options_values, + size_t num_keys) { + return CHECK_STATUS(SessionOptionsAppendExecutionProvider, session_options, name, provider_options_keys, provider_options_values, num_keys); } int OrtAddFreeDimensionOverride(ort_session_options_handle_t session_options, @@ -211,6 +223,113 @@ int OrtGetInputOutputCount(OrtSession* session, size_t* input_count, size_t* out return ORT_OK; } +int OrtGetInputOutputMetadata(ort_session_handle_t session, size_t index, char** name_cstr_ptr, void** type_info_ptr) { + OrtAllocator* allocator = nullptr; + RETURN_ERROR_CODE_IF_ERROR(GetAllocatorWithDefaultOptions, &allocator); + + size_t input_count, output_count; + int error_code = OrtGetInputOutputCount(session, &input_count, &output_count); + if (error_code != ORT_OK) { + return error_code; + } + + if (index >= input_count + output_count) { + std::ostringstream ostr; + ostr << "Invalid index: " << index << ", input count: " << input_count << ", output count: " << output_count; + return CheckStatus(Ort::GetApi().CreateStatus(ORT_INVALID_ARGUMENT, ostr.str().c_str())); + } + + char* name_cstr; + if (index < input_count) { + RETURN_ERROR_CODE_IF_ERROR(SessionGetInputName, session, index, allocator, &name_cstr); + } else { + RETURN_ERROR_CODE_IF_ERROR(SessionGetOutputName, session, index - input_count, allocator, &name_cstr); + } + REGISTER_AUTO_RELEASE_BUFFER(char, name_cstr, allocator); + + OrtTypeInfo* type_info; + if (index < input_count) { + RETURN_ERROR_CODE_IF_ERROR(SessionGetInputTypeInfo, session, index, &type_info); + } else { + RETURN_ERROR_CODE_IF_ERROR(SessionGetOutputTypeInfo, session, index - input_count, &type_info); + } + REGISTER_AUTO_RELEASE_HANDLE(TypeInfo, type_info); + + const OrtTensorTypeAndShapeInfo* tensor_info; + RETURN_ERROR_CODE_IF_ERROR(CastTypeInfoToTensorInfo, type_info, &tensor_info); + + size_t type_info_size = 4; + ONNXTensorElementDataType element_type = ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED; + size_t dim_count = 0; + if (tensor_info != nullptr) { + RETURN_ERROR_CODE_IF_ERROR(GetTensorElementType, tensor_info, &element_type); + RETURN_ERROR_CODE_IF_ERROR(GetDimensionsCount, tensor_info, &dim_count); + + // byte [0, 4): [i32] element type + // byte [4, 8): [u32] dimension count + // byte [8, 8 + dim_count * ptr_size): [ptr] symbolic dimension names for dim[0], dim[1], ..., dim[dim_count - 1] + // byte [8 + dim_count * ptr_size, 8 + dim_count * ptr_size * 2): [size_t] dimension values for dim[0], dim[1], ..., dim[dim_count - 1] + // from byte 8 + dim_count * ptr_size * 2: optional string copies for symbolic dimension names + type_info_size = 8 + dim_count * (sizeof(size_t) * 2); + } + + std::vector dim_values(dim_count); + std::vector dim_params(dim_count); + std::vector dim_params_str_len(dim_count); + if (dim_count > 0) { + size_t str_len_total = 0; + RETURN_ERROR_CODE_IF_ERROR(GetDimensions, tensor_info, dim_values.data(), dim_count); + RETURN_ERROR_CODE_IF_ERROR(GetSymbolicDimensions, tensor_info, dim_params.data(), dim_count); + for (size_t i = 0; i < dim_count; ++i) { + size_t str_size = dim_params[i] ? strlen(dim_params[i]) : 0; + if (str_size > 0) { + str_len_total += str_size + 1; + dim_params_str_len[i] = str_size + 1; + } else { + dim_params_str_len[i] = 0; + } + } + type_info_size += str_len_total; + } + + uint8_t* type_info_buffer = reinterpret_cast(allocator->Alloc(allocator, type_info_size)); + // write to buffer @ byte [0, 4) + int32_t* p_type_info_element_type = reinterpret_cast(type_info_buffer); + *p_type_info_element_type = static_cast(element_type); + + if (tensor_info != nullptr) { + // write to buffer @ byte [4, 8) + uint32_t* p_type_info_dim_count = reinterpret_cast(type_info_buffer + 4); + *p_type_info_dim_count = static_cast(dim_count); + + if (dim_count > 0) { + // write to buffer @ byte [8, 8 + dim_count * ptr_size) + const char** p_dim_params = reinterpret_cast(type_info_buffer + 8); + char* p_str_copy_dest = reinterpret_cast(type_info_buffer + 8 + dim_count * sizeof(size_t) * 2); + for (size_t i = 0; i < dim_count; ++i) { + if (dim_params_str_len[i] > 0) { + p_dim_params[i] = p_str_copy_dest; + memcpy(p_str_copy_dest, dim_params[i], dim_params_str_len[i]); + p_str_copy_dest += dim_params_str_len[i]; + } else { + p_dim_params[i] = nullptr; + } + } + + // write to buffer @ byte [8 + dim_count * ptr_size, 8 + dim_count * ptr_size + dim_count * 4 + dim_count * 4) + size_t* p_dim_values = reinterpret_cast(type_info_buffer + 8 + dim_count * sizeof(size_t)); + for (size_t i = 0; i < dim_count; ++i) { + p_dim_values[i] = static_cast(dim_values[i]); + } + } + } + + UNREGISTER_AUTO_RELEASE(name_cstr); + *name_cstr_ptr = name_cstr; + *type_info_ptr = type_info_buffer; + return ORT_OK; +} + char* OrtGetInputName(OrtSession* session, size_t index) { OrtAllocator* allocator = nullptr; RETURN_NULLPTR_IF_ERROR(GetAllocatorWithDefaultOptions, &allocator); @@ -507,6 +626,16 @@ char* OrtEndProfiling(ort_session_handle_t session) { : nullptr; } +// WebGPU API Section + +#ifdef USE_WEBGPU + +WGPUDevice OrtGetWebGpuDevice(int device_id) { + return onnxruntime::webgpu::GetDevice(device_id); +} + +#endif + // Training API Section #ifdef ENABLE_TRAINING_APIS diff --git a/onnxruntime/wasm/api.h b/onnxruntime/wasm/api.h index f44c515d98f6b..c488c16f4a60c 100644 --- a/onnxruntime/wasm/api.h +++ b/onnxruntime/wasm/api.h @@ -10,6 +10,10 @@ #include +#ifdef USE_WEBGPU +#include +#endif + #include struct OrtSession; @@ -85,7 +89,10 @@ ort_session_options_handle_t EMSCRIPTEN_KEEPALIVE OrtCreateSessionOptions(size_t * @returns ORT error code. If not zero, call OrtGetLastError() to get detailed error message. */ int EMSCRIPTEN_KEEPALIVE OrtAppendExecutionProvider(ort_session_options_handle_t session_options, - const char* name); + const char* name, + const char* const* provider_options_keys, + const char* const* provider_options_values, + size_t num_keys); /** * add a free dimension override for one dimension of a session's input. @@ -138,21 +145,17 @@ int EMSCRIPTEN_KEEPALIVE OrtGetInputOutputCount(ort_session_handle_t session, size_t* output_count); /** - * get the model's input name. + * get the metadata of the specified input or output of the model. * @param session handle of the specified session - * @param index the input index - * @returns a pointer to a buffer which contains C-style string. Caller must release the C style string after use by + * @param index the input index or output index. index should be in range [0, input_count + output_count). if the index + * is in range [0, input_count), it's an input index. otherwise, it's an output index. + * @param name_cstr_ptr [out] a pointer to a buffer which contains C-style string of the name of the input or output. Caller must release the C style string after use by * calling OrtFree(). - */ -char* EMSCRIPTEN_KEEPALIVE OrtGetInputName(ort_session_handle_t session, size_t index); -/** - * get the model's output name. - * @param session handle of the specified session - * @param index the output index - * @returns a pointer to a buffer which contains C-style string. Caller must release the C style string after use by + * @param type_info_ptr [out] a pointer to a buffer which contains the type information of the input or output. Caller must release the buffer after use by * calling OrtFree(). + * @returns ORT error code. If not zero, call OrtGetLastError() to get detailed error message. */ -char* EMSCRIPTEN_KEEPALIVE OrtGetOutputName(ort_session_handle_t session, size_t index); +int EMSCRIPTEN_KEEPALIVE OrtGetInputOutputMetadata(ort_session_handle_t session, size_t index, char** name_cstr_ptr, void** type_info_ptr); /** * free the specified buffer. @@ -294,6 +297,21 @@ int EMSCRIPTEN_KEEPALIVE OrtRun(ort_session_handle_t session, */ char* EMSCRIPTEN_KEEPALIVE OrtEndProfiling(ort_session_handle_t session); +// WebGPU API Section + +#ifdef USE_WEBGPU + +/** + * get the GPU Device by device ID. + * + * This function is only available after the GPU Device is initialized in WebGpuContextFactory. + * + * @returns a WGPUDevice handle. + */ +WGPUDevice EMSCRIPTEN_KEEPALIVE OrtGetWebGpuDevice(int device_id); + +#endif + // Training API Section #ifdef ENABLE_TRAINING_APIS diff --git a/onnxruntime/wasm/js_post_js.js b/onnxruntime/wasm/js_post_js.js index b77d82fbd7d10..56d3246fd07f0 100644 --- a/onnxruntime/wasm/js_post_js.js +++ b/onnxruntime/wasm/js_post_js.js @@ -2,6 +2,4 @@ // Licensed under the MIT License. -'use strict'; - Module["PTR_SIZE"] = 4; diff --git a/onnxruntime/wasm/js_post_js_64.js b/onnxruntime/wasm/js_post_js_64.js index b140df927ebbd..cfd79523f7900 100644 --- a/onnxruntime/wasm/js_post_js_64.js +++ b/onnxruntime/wasm/js_post_js_64.js @@ -2,6 +2,4 @@ // Licensed under the MIT License. -'use strict'; - Module["PTR_SIZE"] = 8; diff --git a/onnxruntime/wasm/post-webgpu.js b/onnxruntime/wasm/post-webgpu.js new file mode 100644 index 0000000000000..146355f6a44d3 --- /dev/null +++ b/onnxruntime/wasm/post-webgpu.js @@ -0,0 +1,261 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// +// This file contains the post-run code for the ORT WebAssembly module. The code in this file will be injected into the +// final module using Emscripten's `--post-js` option. +// +// This file will only be used in build with flag `--use_webgpu`. + +/** + * This function is called only once when initializing the WebGPU backend. + * + * @param {(gpuDevice: GPUDevice) => void} setDefaultDevice A callback function to set the default device. + */ +Module["webgpuInit"] = (setDefaultDevice) => { + /** + * a map from GPUDevice to [deviceId, instanceHandle, deviceHandle] + * + * only stores custom devices (ie. devices created by the user, not the default device created by ORT) + * + * key is the GPUDevice object. + * + * value is a tuple of 3 elements: + * - deviceId: a unique ID for the device. Must be positive integer. + * - instanceHandle: the instance handle(pointer) of the device. + * - deviceHandle: the device handle(pointer) of the device. + * + * @type {WeakMap} + */ + const webgpuActiveDevices = new WeakMap(); + /** + * a number that is used to assign a unique ID to the next custom device. + */ + let webgpuNextDeviceId = 1; + /** + * a function to set the default device. + * + * @type {(gpuDevice: GPUDevice) => void} + */ + const webgpuSetDefaultDevice = setDefaultDevice; + /** + * the current device that is being used to create a WebGPU EP inference session. + * + * the value of this variable is only valid during the creation of a WebGPU EP inference session. + * + * @type {GPUDevice|undefined} + */ + let webgpuCurrentDevice = undefined; + /** + * the current device ID that is being used to create a WebGPU EP inference session. + * + * the value of this variable is only valid during the creation of a WebGPU EP inference session. + * + * @type {number|undefined} + */ + let webgpuCurrentDeviceId = undefined; + + /** + * This function is called only when a custom device is used, during preparation of session options. + * + * @param {GPUDevice} device the user provided device object. + * @returns {undefined|[number, number, number]} a tuple of device id, instance handle, and device handle. + */ + Module["webgpuRegisterDevice"] = (device) => { + if (webgpuCurrentDeviceId !== undefined) { + throw new Error("another WebGPU EP inference session is being created."); + } + + if (device) { + let deviceInfo = webgpuActiveDevices.get(device); + if (!deviceInfo) { + const instanceHandle = _wgpuCreateInstance(0); + const deviceHandle = WebGPU.importJsDevice(device, instanceHandle); + deviceInfo = [webgpuNextDeviceId++, instanceHandle, deviceHandle]; + webgpuActiveDevices.set(device, deviceInfo); + } + + // The current device ID is a temporary storage for the device ID to be used in the session that is being created. + // + // Soon after `webgpuRegisterDevice` (this function) is called, `webgpuOnCreateSession` will be called so that the + // value of `webgpuCurrentDeviceId` is used and reset then. + webgpuCurrentDevice = device; + webgpuCurrentDeviceId = deviceInfo[0]; + return deviceInfo; + } else { + webgpuCurrentDevice = undefined; + webgpuCurrentDeviceId = 0; + return undefined; + } + }; + + const webgpuActiveSessions = new Map(); + Module["webgpuOnCreateSession"] = (sessionHandle) => { + if (webgpuCurrentDeviceId === undefined) { + // do nothing if webgpuCurrentDeviceId is undefined. + // this means no WebGPU EP is being created. + return; + } + + const deviceId = webgpuCurrentDeviceId; + webgpuCurrentDeviceId = undefined; + + if (sessionHandle) { + // when session created successfully + const deviceHandle = _OrtGetWebGpuDevice(deviceId); + webgpuActiveSessions.set(sessionHandle, deviceHandle); + + if (deviceId === 0) { + const device = webgpuCurrentDevice ?? WebGPU.getJsObject(deviceHandle); + webgpuSetDefaultDevice(device); + } + } + webgpuCurrentDevice = undefined; + }; + + Module["webgpuOnReleaseSession"] = (sessionHandle) => { + webgpuActiveSessions.delete(sessionHandle); + }; + + const gpuBufferMetadataSymbol = Symbol("gpuBufferMetadata"); + + Module["webgpuRegisterBuffer"] = (buffer, sessionHandle, bufferHandle) => { + if (bufferHandle) { + // This is a buffer that was created by ORT. Metadata is [bufferHandle, NaN] + + buffer[gpuBufferMetadataSymbol] = [bufferHandle, NaN]; + return bufferHandle; + } else { + // This is a buffer that was created by the user. Metadata is [bufferHandle, refCount] + + const metadata = buffer[gpuBufferMetadataSymbol]; + if (metadata) { + metadata[1]++; + return metadata[0]; + } + + const deviceHandle = webgpuActiveSessions.get(sessionHandle); + if (deviceHandle === undefined) { + throw new Error( + "Invalid session handle passed to webgpuRegisterBuffer" + ); + } + + const bufferHandle = WebGPU.importJsBuffer(buffer, deviceHandle); + buffer[gpuBufferMetadataSymbol] = [bufferHandle, 1]; + return bufferHandle; + } + }; + + Module["webgpuUnregisterBuffer"] = (buffer) => { + const metadata = buffer[gpuBufferMetadataSymbol]; + if (!metadata) { + throw new Error("Buffer is not registered"); + } + metadata[1]--; + // For buffers created by ORT, metadata[1] will always be NaN. This function will not release the buffer. + // Instead, the buffer will be released when user calls `Tensor.dispose()` in JavaScript. + if (metadata[1] === 0) { + _wgpuBufferRelease(metadata[0]); + delete buffer[gpuBufferMetadataSymbol]; + } + }; + + Module["webgpuGetBuffer"] = (bufferHandle) => { + return WebGPU.getJsObject(bufferHandle); + }; + + Module["webgpuCreateDownloader"] = (gpuBuffer, bufferSize, sessionHandle) => { + const deviceHandle = webgpuActiveSessions.get(sessionHandle); + if (deviceHandle === undefined) { + throw new Error("Invalid session handle passed to webgpuRegisterBuffer"); + } + + const buffer = gpuBuffer; + const device = WebGPU.getJsObject(deviceHandle); + const originalSize = bufferSize; + const size = Math.ceil(Number(originalSize) / 16) * 16; + + return async () => { + // prettier-ignore + // + // the line above is used to force prettier to skip formatting the next statement. + // this is because prettier will remove the quotes around the property names, but we need to keep them + // because otherwise closure compiler may rename them and break the code. + const gpuReadBufferDescriptor = { + "size": size, + "usage": 9 /* GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ */, + }; + const gpuReadBuffer = device.createBuffer(gpuReadBufferDescriptor); + try { + const commandEncoder = device.createCommandEncoder(); + commandEncoder.copyBufferToBuffer( + buffer /* source buffer */, + 0 /* source offset */, + gpuReadBuffer /* destination buffer */, + 0 /* destination offset */, + size /* size */ + ); + device.queue.submit([commandEncoder.finish()]); + + await gpuReadBuffer.mapAsync(GPUMapMode.READ); + + const arrayBuffer = gpuReadBuffer.getMappedRange(); + return arrayBuffer.slice(0, originalSize); + } finally { + gpuReadBuffer.destroy(); + } + }; + }; + + // Setup a callback function for loading external buffers (model weights). + Module.webgpuUploadExternalBuffer = (bufferHandle, data) => { + const srcArrayBuffer = data.buffer; + const srcOffset = data.byteOffset; + const srcLength = data.byteLength; + const size = Math.ceil(Number(srcLength) / 16) * 16; + + const gpuBuffer = WebGPU.getJsObject(bufferHandle); + + // get current device + if (!webgpuCurrentDevice) { + const deviceHandle = _OrtGetWebGpuDevice(webgpuCurrentDeviceId); + webgpuCurrentDevice = WebGPU.getJsObject(deviceHandle); + } + + // create gpu buffer + + // prettier-ignore + // + // the line above is used to force prettier to skip formatting the next statement. + // this is because prettier will remove the quotes around the property names, but we need to keep them + // because otherwise closure compiler may rename them and break the code. + const gpuBufferForUploadingDescriptor = { + "mappedAtCreation": true, + "size": size, + "usage": 6 /* GPUBufferUsage.MAP_WRITE | GPUBufferUsage.COPY_SRC */, + }; + const gpuBufferForUploading = webgpuCurrentDevice.createBuffer( + gpuBufferForUploadingDescriptor + ); + + // copy (upload) data + const arrayBuffer = gpuBufferForUploading.getMappedRange(); + new Uint8Array(arrayBuffer).set( + new Uint8Array(srcArrayBuffer, srcOffset, srcLength) + ); + gpuBufferForUploading.unmap(); + + // GPU copy + const commandEncoder = webgpuCurrentDevice.createCommandEncoder(); + commandEncoder.copyBufferToBuffer( + gpuBufferForUploading, + 0, + gpuBuffer, + 0, + size + ); + webgpuCurrentDevice.queue.submit([commandEncoder.finish()]); + gpuBufferForUploading.destroy(); + }; +}; diff --git a/onnxruntime/wasm/pre-async.js b/onnxruntime/wasm/pre-async.js new file mode 100644 index 0000000000000..8c75dc7c5cf1e --- /dev/null +++ b/onnxruntime/wasm/pre-async.js @@ -0,0 +1,132 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// +// This file contains the pre-run code for the ORT WebAssembly module. The code in this file will be injected into the +// final module using Emscripten's `--pre-js` option. +// +// This file will only be used in build with flag `-s ASYNCIFY=1`. + +/** + * initialize for asyncify support. + */ +let initAsyncImpl = () => { + // This is a simplified version of cwrap() with options.async === true (-sASYNCIFY=1) + // It removes some overhead in cwarp() and ccall() that we don't need. + // + // Currently in ASYNCIFY build, we only use this for the following functions: + // - OrtCreateSession() + // - OrtRun() + // - OrtRunWithBinding() + // - OrtBindInput() + // + // Note: about parameters "getFunc" and "setFunc": + // - Emscripten has different behaviors for Debug and Release builds for generating exported function wrapper. + // + // - In Debug build, it will generate a wrapper function for each exported function. For example, it generates a + // wrapper for OrtRun() like this (minified): + // ``` + // var _OrtRun = Module["_OrtRun"] = createExportWrapper("OrtRun"); + // ``` + // + // - In Release build, it will generate a lazy loading wrapper for each exported function. For example, it generates + // a wrapper for OrtRun() like this (minified): + // ``` + // d._OrtRun = (a, b, c, e, f, h, l, q) => (d._OrtRun = J.ka)(a, b, c, e, f, h, l, q); + // ``` + // + // The behavior of these two wrappers are different. The debug build will assign `Module["_OrtRun"]` only once + // because `createExportWrapper()` does not reset `Module["_OrtRun"]` inside. The release build, however, will + // reset d._OrtRun to J.ka when the first time it is called. + // + // The difference is important because we need to design the async wrapper in a way that it can handle both cases. + // + // Now, let's look at how the async wrapper is designed to work for both cases: + // + // - Debug build: + // 1. When Web assembly is being loaded, `Module["_OrtRun"]` is assigned to `createExportWrapper("OrtRun")`. + // 2. When the first time `Module["initAsync"]` is called, `Module["_OrtRun"]` is re-assigned to a new async + // wrapper function. + // Value of `Module["_OrtRun"]` will not be changed again. + // + // - Release build: + // 1. When Web assembly is being loaded, `Module["_OrtRun"]` is assigned to a lazy loading wrapper function. + // 2. When the first time `Module["initAsync"]` is called, `Module["_OrtRun"]` is re-assigned to a new async + // wrapper function. + // 3. When the first time `Module["_OrtRun"]` is called, the async wrapper will be called. It will call into this + // function: + // ``` + // (a, b, c, e, f, h, l, q) => (d._OrtRun = J.ka)(a, b, c, e, f, h, l, q); + // ``` + // This function will assign d._OrtRun (ie. the minimized `Module["_OrtRun"]`) to the real function (J.ka). + // 4. Since d._OrtRun is re-assigned, we need to update the async wrapper to re-assign its stored + // function to the updated value (J.ka), and re-assign the value of `d._OrtRun` back to the async wrapper. + // Value of `Module["_OrtRun"]` will not be changed again. + // + // The value of `Module["_OrtRun"]` will need to be assigned for 2 times for debug build and 4 times for release + // build. + // + // This is why we need this `getFunc` and `setFunc` parameters. They are used to get the current value of an + // exported function and set the new value of an exported function. + // + const wrapAsync = (func, getFunc, setFunc) => { + return (...args) => { + // cache the async data before calling the function. + const previousAsync = Asyncify.currData; + + const previousFunc = getFunc?.(); + const ret = func(...args); + const newFunc = getFunc?.(); + if (previousFunc !== newFunc) { + // The exported function has been updated. + // Set the sync function reference to the new function. + func = newFunc; + // Set the exported function back to the async wrapper. + setFunc(previousFunc); + // Remove getFunc and setFunc. They are no longer needed. + setFunc = null; + getFunc = null; + } + + // If the async data has been changed, it means that the function started an async operation. + if (Asyncify.currData != previousAsync) { + // returns the promise + return Asyncify.whenDone(); + } + // the function is synchronous. returns the result. + return ret; + }; + }; + + // replace the original functions with asyncified versions + const wrapAsyncAPIs = (funcNames) => { + for (const funcName of funcNames) { + Module[funcName] = wrapAsync( + Module[funcName], + () => Module[funcName], + (v) => (Module[funcName] = v) + ); + } + }; + + wrapAsyncAPIs([ + "_OrtAppendExecutionProvider", + "_OrtCreateSession", + "_OrtRun", + "_OrtRunWithBinding", + "_OrtBindInput", + ]); + + // If JSEP is enabled, wrap OrtRun() and OrtRunWithBinding() with asyncify. + if (typeof jsepRunAsync !== "undefined") { + Module["_OrtRun"] = jsepRunAsync(Module["_OrtRun"]); + Module["_OrtRunWithBinding"] = jsepRunAsync(Module["_OrtRunWithBinding"]); + } + + // remove this function to make sure it is called only once. + initAsyncImpl = undefined; +}; + +Module["asyncInit"] = () => { + initAsyncImpl?.(); +}; diff --git a/onnxruntime/wasm/pre-jsep.js b/onnxruntime/wasm/pre-jsep.js index 0c83e71a921cb..cca8da0525fbe 100644 --- a/onnxruntime/wasm/pre-jsep.js +++ b/onnxruntime/wasm/pre-jsep.js @@ -1,255 +1,159 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -'use strict'; - // // This file contains the pre-run code for the ORT WebAssembly module. The code in this file will be injected into the // final module using Emscripten's `--pre-js` option. // // This file will only be used in build with flag `--use_jsep`. - -/** - * initialize JSEP for asyncify support. - */ -let jsepInitAsync = () => { - // This is a simplified version of cwrap() with options.async === true (-sASYNCIFY=1) - // It removes some overhead in cwarp() and ccall() that we don't need. - // - // Currently in JSEP build, we only use this for the following functions: - // - OrtRun() - // - OrtRunWithBinding() - // - OrtBindInput() - // - // Note: about parameters "getFunc" and "setFunc": - // - Emscripten has different behaviors for Debug and Release builds for generating exported function wrapper. - // - // - In Debug build, it will generate a wrapper function for each exported function. For example, it generates a - // wrapper for OrtRun() like this (minified): - // ``` - // var _OrtRun = Module["_OrtRun"] = createExportWrapper("OrtRun"); - // ``` - // - // - In Release build, it will generate a lazy loading wrapper for each exported function. For example, it generates - // a wrapper for OrtRun() like this (minified): - // ``` - // d._OrtRun = (a, b, c, e, f, h, l, q) => (d._OrtRun = J.ka)(a, b, c, e, f, h, l, q); - // ``` - // - // The behavior of these two wrappers are different. The debug build will assign `Module["_OrtRun"]` only once - // because `createExportWrapper()` does not reset `Module["_OrtRun"]` inside. The release build, however, will - // reset d._OrtRun to J.ka when the first time it is called. - // - // The difference is important because we need to design the async wrapper in a way that it can handle both cases. - // - // Now, let's look at how the async wrapper is designed to work for both cases: - // - // - Debug build: - // 1. When Web assembly is being loaded, `Module["_OrtRun"]` is assigned to `createExportWrapper("OrtRun")`. - // 2. When the first time `Module["jsepInit"]` is called, `Module["_OrtRun"]` is re-assigned to a new async - // wrapper function. - // Value of `Module["_OrtRun"]` will not be changed again. - // - // - Release build: - // 1. When Web assembly is being loaded, `Module["_OrtRun"]` is assigned to a lazy loading wrapper function. - // 2. When the first time `Module["jsepInit"]` is called, `Module["_OrtRun"]` is re-assigned to a new async - // wrapper function. - // 3. When the first time `Module["_OrtRun"]` is called, the async wrapper will be called. It will call into this - // function: - // ``` - // (a, b, c, e, f, h, l, q) => (d._OrtRun = J.ka)(a, b, c, e, f, h, l, q); - // ``` - // This function will assign d._OrtRun (ie. the minimized `Module["_OrtRun"]`) to the real function (J.ka). - // 4. Since d._OrtRun is re-assigned, we need to update the async wrapper to re-assign its stored - // function to the updated value (J.ka), and re-assign the value of `d._OrtRun` back to the async wrapper. - // Value of `Module["_OrtRun"]` will not be changed again. - // - // The value of `Module["_OrtRun"]` will need to be assigned for 2 times for debug build and 4 times for release - // build. - // - // This is why we need this `getFunc` and `setFunc` parameters. They are used to get the current value of an - // exported function and set the new value of an exported function. - // - const jsepWrapAsync = (func, getFunc, setFunc) => { - return (...args) => { - // cache the async data before calling the function. - const previousAsync = Asyncify.currData; - - const previousFunc = getFunc?.(); - const ret = func(...args); - const newFunc = getFunc?.(); - if (previousFunc !== newFunc) { - // The exported function has been updated. - // Set the sync function reference to the new function. - func = newFunc; - // Set the exported function back to the async wrapper. - setFunc(previousFunc); - // Remove getFunc and setFunc. They are no longer needed. - setFunc = null; - getFunc = null; - } - - // If the async data has been changed, it means that the function started an async operation. - if (Asyncify.currData != previousAsync) { - // returns the promise - return Asyncify.whenDone(); +// This is a wrapper for OrtRun() and OrtRunWithBinding() to ensure that Promises are handled correctly. +const jsepRunAsync = (runAsyncFunc) => { + return async (...args) => { + try { + // Module.jsepSessionState should be null, unless we are in the middle of a session. + // If it is not null, it means that the previous session has not finished yet. + if (Module.jsepSessionState) { + throw new Error("Session already started"); } - // the function is synchronous. returns the result. - return ret; - }; - }; + const state = (Module.jsepSessionState = { + sessionHandle: args[0], + errors: [], + }); - // This is a wrapper for OrtRun() and OrtRunWithBinding() to ensure that Promises are handled correctly. - const runAsync = (runAsyncFunc) => { - return async (...args) => { - try { - // Module.jsepSessionState should be null, unless we are in the middle of a session. - // If it is not null, it means that the previous session has not finished yet. - if (Module.jsepSessionState) { - throw new Error('Session already started'); - } - const state = Module.jsepSessionState = {sessionHandle: args[0], errors: []}; + // Run the acyncified function: OrtRun() or OrtRunWithBinding() + const ret = await runAsyncFunc(...args); - // Run the acyncified function: OrtRun() or OrtRunWithBinding() - const ret = await runAsyncFunc(...args); - - // Check if the session is still valid. this object should be the same as the one we set above. - if (Module.jsepSessionState !== state) { - throw new Error('Session mismatch'); - } + // Check if the session is still valid. this object should be the same as the one we set above. + if (Module.jsepSessionState !== state) { + throw new Error("Session mismatch"); + } - // Flush the backend. This will submit all pending commands to the GPU. - Module.jsepBackend?.['flush'](); + // Flush the backend. This will submit all pending commands to the GPU. + Module.jsepBackend?.["flush"](); - // Await all pending promises. This includes GPU validation promises for diagnostic purposes. - const errorPromises = state.errors; - if (errorPromises.length > 0) { - let errors = await Promise.all(errorPromises); - errors = errors.filter(e => e); - if (errors.length > 0) { - throw new Error(errors.join('\n')); - } + // Await all pending promises. This includes GPU validation promises for diagnostic purposes. + const errorPromises = state.errors; + if (errorPromises.length > 0) { + let errors = await Promise.all(errorPromises); + errors = errors.filter((e) => e); + if (errors.length > 0) { + throw new Error(errors.join("\n")); } - - return ret; - } finally { - Module.jsepSessionState = null; } - }; - }; - - // replace the original functions with asyncified versions - Module['_OrtCreateSession'] = jsepWrapAsync( - Module['_OrtCreateSession'], - () => Module['_OrtCreateSession'], - v => Module['_OrtCreateSession'] = v); - Module['_OrtRun'] = runAsync(jsepWrapAsync( - Module['_OrtRun'], - () => Module['_OrtRun'], - v => Module['_OrtRun'] = v)); - Module['_OrtRunWithBinding'] = runAsync(jsepWrapAsync( - Module['_OrtRunWithBinding'], - () => Module['_OrtRunWithBinding'], - v => Module['_OrtRunWithBinding'] = v)); - Module['_OrtBindInput'] = jsepWrapAsync( - Module['_OrtBindInput'], - () => Module['_OrtBindInput'], - v => Module['_OrtBindInput'] = v); - // remove this function to make sure it is called only once. - jsepInitAsync = undefined; + return ret; + } finally { + Module.jsepSessionState = null; + } + }; }; - /** - * initialize JSEP for WebGPU. + * initialize JSEP for WebGPU and WebNN. */ -Module['jsepInit'] = (name, params) => { - jsepInitAsync?.(); - - if (name === 'webgpu') { - [Module.jsepBackend, - Module.jsepAlloc, - Module.jsepFree, - Module.jsepCopy, - Module.jsepCopyAsync, - Module.jsepCreateKernel, - Module.jsepReleaseKernel, - Module.jsepRunKernel, - Module.jsepCaptureBegin, - Module.jsepCaptureEnd, - Module.jsepReplay] = params; +Module["jsepInit"] = (name, params) => { + if (name === "webgpu") { + [ + Module.jsepBackend, + Module.jsepAlloc, + Module.jsepFree, + Module.jsepCopy, + Module.jsepCopyAsync, + Module.jsepCreateKernel, + Module.jsepReleaseKernel, + Module.jsepRunKernel, + Module.jsepCaptureBegin, + Module.jsepCaptureEnd, + Module.jsepReplay, + ] = params; // expose webgpu backend functions const backend = Module.jsepBackend; - Module['jsepRegisterBuffer'] = (sessionId, index, buffer, size) => { - return backend['registerBuffer'](sessionId, index, buffer, size); + Module["jsepRegisterBuffer"] = (sessionId, index, buffer, size) => { + return backend["registerBuffer"](sessionId, index, buffer, size); }; - Module['jsepGetBuffer'] = (dataId) => { - return backend['getBuffer'](dataId); + Module["jsepGetBuffer"] = (dataId) => { + return backend["getBuffer"](dataId); }; - Module['jsepCreateDownloader'] = (gpuBuffer, size, type) => { - return backend['createDownloader'](gpuBuffer, size, type); + Module["jsepCreateDownloader"] = (gpuBuffer, size, type) => { + return backend["createDownloader"](gpuBuffer, size, type); }; - Module['jsepOnCreateSession'] = sessionId => { - backend['onCreateSession'](sessionId); + Module["jsepOnCreateSession"] = (sessionId) => { + backend["onCreateSession"](sessionId); }; - Module['jsepOnReleaseSession'] = sessionId => { - backend['onReleaseSession'](sessionId); + Module["jsepOnReleaseSession"] = (sessionId) => { + backend["onReleaseSession"](sessionId); }; - Module['jsepOnRunStart'] = sessionId => { - return backend['onRunStart'](sessionId); + Module["jsepOnRunStart"] = (sessionId) => { + return backend["onRunStart"](sessionId); }; Module.jsepUploadExternalBuffer = (dataId, buffer) => { - backend['upload'](dataId, buffer); + backend["upload"](dataId, buffer); }; - } else if (name === 'webnn') { + } else if (name === "webnn") { // Functions called from EM_ASM need to be assigned in a way that can be minified. // Functions called via emscripten::val::module_property need to be assigned by name so that the minifier doesn't // change the name. - [Module.jsepBackend, - Module.jsepReserveTensorId, - Module.jsepReleaseTensorId, - Module['jsepEnsureTensor'], - Module.jsepUploadTensor, - Module['jsepDownloadTensor'], - ] = params; + const backend = params[0]; + [ + Module.webnnReserveTensorId, + Module.webnnReleaseTensorId, + Module["webnnEnsureTensor"], + Module.webnnUploadTensor, + Module["webnnDownloadTensor"], + ] = params.slice(1); // This function is called from both JS and an EM_ASM block, it needs both a minifiable name and an explicit name. - Module['jsepReleaseTensorId'] = Module.jsepReleaseTensorId; - Module['jsepUploadTensor'] = Module.jsepUploadTensor; + Module["webnnReleaseTensorId"] = Module.webnnReleaseTensorId; + Module["webnnUploadTensor"] = Module.webnnUploadTensor; // Functions called from JS also need to have explicit names. - const backend = Module.jsepBackend; - Module['jsepOnRunStart'] = sessionId => { - return backend['onRunStart'](sessionId); + Module["webnnOnRunStart"] = (sessionId) => { + return backend["onRunStart"](sessionId); }; - Module['jsepOnRunEnd'] = backend['onRunEnd'].bind(backend); - Module['jsepRegisterMLContext'] = (sessionId, mlContext) => { - backend['registerMLContext'](sessionId, mlContext); + Module["webnnOnRunEnd"] = backend["onRunEnd"].bind(backend); + Module["webnnRegisterMLContext"] = (sessionId, mlContext) => { + backend["registerMLContext"](sessionId, mlContext); }; - Module['jsepOnReleaseSession'] = sessionId => { - backend['onReleaseSession'](sessionId); + Module["webnnOnReleaseSession"] = (sessionId) => { + backend["onReleaseSession"](sessionId); }; - Module['jsepCreateMLTensorDownloader'] = (tensorId, type) => { - return backend['createMLTensorDownloader'](tensorId, type); - } - Module['jsepRegisterMLTensor'] = (sessionId, tensor, dataType, shape) => { - return backend['registerMLTensor'](sessionId, tensor, dataType, shape); + Module["webnnCreateMLTensorDownloader"] = (tensorId, type) => { + return backend["createMLTensorDownloader"](tensorId, type); + }; + Module["webnnRegisterMLTensor"] = (sessionId, tensor, dataType, shape) => { + return backend["registerMLTensor"](sessionId, tensor, dataType, shape); }; - Module['jsepCreateMLContext'] = (optionsOrGpuDevice) => { - return backend['createMLContext'](optionsOrGpuDevice); + Module["webnnCreateMLContext"] = (optionsOrGpuDevice) => { + return backend["createMLContext"](optionsOrGpuDevice); }; - Module['jsepRegisterMLConstant'] = (externalFilePath, dataOffset, dataLength, builder, desc) => { - return backend['registerMLConstant']( - externalFilePath, dataOffset, dataLength, builder, desc, Module.MountedFiles); + Module["webnnRegisterMLConstant"] = ( + externalFilePath, + dataOffset, + dataLength, + builder, + desc, + shouldConvertInt64ToInt32, + ) => { + return backend["registerMLConstant"]( + externalFilePath, + dataOffset, + dataLength, + builder, + desc, + Module.MountedFiles, + shouldConvertInt64ToInt32, + ); }; - Module['jsepRegisterGraphInput'] = backend['registerGraphInput'].bind(backend); - Module['jsepIsGraphInput'] = backend['isGraphInput'].bind(backend); + Module["webnnRegisterGraphInput"] = + backend["registerGraphInput"].bind(backend); + Module["webnnIsGraphInput"] = backend["isGraphInput"].bind(backend); - Module['jsepCreateTemporaryTensor'] = backend['createTemporaryTensor'].bind(backend); + Module["webnnCreateTemporaryTensor"] = + backend["createTemporaryTensor"].bind(backend); + Module["webnnIsInt64Supported"] = backend["isInt64Supported"].bind(backend); } }; diff --git a/onnxruntime/wasm/pre.js b/onnxruntime/wasm/pre.js index 9b5f3ce545b78..636a9713519a7 100644 --- a/onnxruntime/wasm/pre.js +++ b/onnxruntime/wasm/pre.js @@ -1,21 +1,18 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -'use strict'; - // // This file contains the pre-run code for the ORT WebAssembly module. The code in this file will be injected into the // final module using Emscripten's `--pre-js` option. - /** * Mount external data files of a model to an internal map, which will be used during session initialization. * * @param {string} externalDataFilesPath * @param {Uint8Array} externalDataFilesData */ -Module['mountExternalData'] = (externalDataFilePath, externalDataFileData) => { - if (externalDataFilePath.startsWith('./')) { +Module["mountExternalData"] = (externalDataFilePath, externalDataFileData) => { + if (externalDataFilePath.startsWith("./")) { externalDataFilePath = externalDataFilePath.substring(2); } const files = Module.MountedFiles || (Module.MountedFiles = new Map()); @@ -25,7 +22,7 @@ Module['mountExternalData'] = (externalDataFilePath, externalDataFileData) => { /** * Unmount external data files of a model. */ -Module['unmountExternalData'] = () => { +Module["unmountExternalData"] = () => { delete Module.MountedFiles; }; @@ -48,5 +45,7 @@ Module['unmountExternalData'] = () => { * * @suppress {checkVars} */ -var SharedArrayBuffer = globalThis.SharedArrayBuffer ?? - new WebAssembly.Memory({'initial': 0, 'maximum': 0, 'shared': true}).buffer.constructor; +var SharedArrayBuffer = + globalThis.SharedArrayBuffer ?? + new WebAssembly.Memory({ initial: 0, maximum: 0, shared: true }).buffer + .constructor; diff --git a/pyproject.toml b/pyproject.toml index f95fb0ff955a4..09a203772aaf9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,15 @@ convention = "google" [tool.pyright] -exclude = ["onnxruntime/core/flatbuffers/*"] +exclude = [ + "onnxruntime/core/flatbuffers/*", + "cmake/external/**", + "**/node_modules/**", + "**/__pycache__/**", + "**/build/**", + "**/build_*/**", + "**/.DS_Store/**", +] reportMissingImports = false [tool.ruff] diff --git a/setup.py b/setup.py index ced2f28e38778..53e533050b245 100644 --- a/setup.py +++ b/setup.py @@ -356,7 +356,7 @@ def finalize_options(self): "libQnnSaver.so", "libQnnSystem.so", "libHtpPrepare.so", - "onnxruntime_qnn_ctx_gen", + "ep_weight_sharing_ctx_gen", ] dl_libs.extend(qnn_deps) if nightly_build: diff --git a/tools/android_custom_build/Dockerfile b/tools/android_custom_build/Dockerfile index cc8de631aacec..dddd8995ba7d1 100644 --- a/tools/android_custom_build/Dockerfile +++ b/tools/android_custom_build/Dockerfile @@ -55,7 +55,7 @@ WORKDIR /workspace # install Android SDK and tools ENV ANDROID_HOME=~/android-sdk -ENV NDK_VERSION=27.2.12479018 +ENV NDK_VERSION=28.0.13004108 ENV ANDROID_NDK_HOME=${ANDROID_HOME}/ndk/${NDK_VERSION} RUN aria2c -q -d /tmp -o cmdline-tools.zip \ diff --git a/tools/ci_build/build.py b/tools/ci_build/build.py index ecdffbe5fd6a0..0fea6acc110f0 100644 --- a/tools/ci_build/build.py +++ b/tools/ci_build/build.py @@ -35,7 +35,8 @@ def version_to_tuple(version: str) -> tuple: import util.android as android # noqa: E402 from util import ( # noqa: E402 generate_android_triplets, - generate_posix_triplets, + generate_linux_triplets, + generate_macos_triplets, generate_vcpkg_triplets_for_emscripten, generate_windows_triplets, get_logger, @@ -432,6 +433,7 @@ def convert_arg_line_to_args(self, arg_line): platform_group = parser.add_mutually_exclusive_group() platform_group.add_argument("--ios", action="store_true", help="build for ios") platform_group.add_argument("--visionos", action="store_true", help="build for visionOS") + platform_group.add_argument("--tvos", action="store_true", help="build for tvOS") platform_group.add_argument( "--macos", choices=["MacOSX", "Catalyst"], @@ -451,6 +453,11 @@ def convert_arg_line_to_args(self, arg_line): default="", help="Path to visionos toolchain file, or cmake/onnxruntime_visionos.toolchain.cmake will be used", ) + parser.add_argument( + "--tvos_toolchain_file", + default="", + help="Path to tvos toolchain file, or cmake/onnxruntime_tvos.toolchain.cmake will be used", + ) parser.add_argument( "--xcode_code_signing_team_id", default="", help="The development team ID used for code signing in Xcode" ) @@ -503,9 +510,10 @@ def convert_arg_line_to_args(self, arg_line): # WebAssembly build parser.add_argument("--build_wasm", action="store_true", help="Build for WebAssembly") parser.add_argument("--build_wasm_static_lib", action="store_true", help="Build for WebAssembly static library") - parser.add_argument("--emsdk_version", default="4.0.3", help="Specify version of emsdk") + parser.add_argument("--emsdk_version", default="4.0.4", help="Specify version of emsdk") parser.add_argument("--enable_wasm_simd", action="store_true", help="Enable WebAssembly SIMD") + parser.add_argument("--enable_wasm_relaxed_simd", action="store_true", help="Enable WebAssembly Relaxed SIMD") parser.add_argument("--enable_wasm_threads", action="store_true", help="Enable WebAssembly multi-threads support") parser.add_argument( @@ -697,6 +705,7 @@ def convert_arg_line_to_args(self, arg_line): parser.add_argument("--armnn_home", help="Path to ArmNN home dir") parser.add_argument("--armnn_libs", help="Path to ArmNN libraries") parser.add_argument("--build_micro_benchmarks", action="store_true", help="Build ONNXRuntime micro-benchmarks.") + parser.add_argument("--no_kleidiai", action="store_true", help="Disable KleidiAI integration on Arm platforms.") # options to reduce binary size parser.add_argument( @@ -944,7 +953,7 @@ def use_dev_mode(args): return False if args.use_armnn: return False - if (args.ios or args.visionos) and is_macOS(): + if (args.ios or args.visionos or args.tvos) and is_macOS(): return False SYSTEM_COLLECTIONURI = os.getenv("SYSTEM_COLLECTIONURI") # noqa: N806 if SYSTEM_COLLECTIONURI and SYSTEM_COLLECTIONURI != "https://dev.azure.com/onnxruntime/": @@ -1059,6 +1068,8 @@ def generate_vcpkg_install_options(build_dir, args): if args.disable_exceptions: folder_name_parts.append("noexception") if len(folder_name_parts) == 0: + # It's hard to tell whether we must use a custom triplet or not. The official triplets work fine for most common situations. However, if a Windows build has set msvc toolset version via args.msvc_toolset then we need to, because we need to ensure all the source code are compiled by the same MSVC toolset version otherwise we will hit link errors like "error LNK2019: unresolved external symbol __std_mismatch_4 referenced in function ..." + # So, to be safe we always use a custom triplet. folder_name = "default" else: folder_name = "_".join(folder_name_parts) @@ -1068,6 +1079,10 @@ def generate_vcpkg_install_options(build_dir, args): if "AGENT_TEMPDIRECTORY" in os.environ: temp_dir = os.environ["AGENT_TEMPDIRECTORY"] vcpkg_install_options.append(f"--x-buildtrees-root={temp_dir}") + elif "RUNNER_TEMP" in os.environ: + temp_dir = os.environ["RUNNER_TEMP"] + vcpkg_install_options.append(f"--x-buildtrees-root={temp_dir}") + vcpkg_install_options.append("--binarysource=clear\\;x-gha,readwrite") # Config asset cache if args.use_vcpkg_ms_internal_asset_cache: @@ -1115,7 +1130,6 @@ def generate_build_tree( cmake_extra_args, ): log.info("Generating CMake build tree") - cmake_dir = os.path.join(source_dir, "cmake") cmake_args = [cmake_path, cmake_dir] if not use_dev_mode(args): @@ -1249,7 +1263,6 @@ def generate_build_tree( ) if args.use_vcpkg: - # TODO: set VCPKG_PLATFORM_TOOLSET_VERSION # Setup CMake flags for vcpkg # Find VCPKG's toolchain cmake file @@ -1270,7 +1283,10 @@ def generate_build_tree( # Fallback to checkout vcpkg from github vcpkg_installation_root = os.path.join(os.path.abspath(build_dir), "vcpkg") if not os.path.exists(vcpkg_installation_root): - run_subprocess(["git", "clone", "https://github.com/microsoft/vcpkg.git", "--recursive"], cwd=build_dir) + run_subprocess( + ["git", "clone", "-b", "2025.03.19", "https://github.com/microsoft/vcpkg.git", "--recursive"], + cwd=build_dir, + ) vcpkg_toolchain_path = Path(vcpkg_installation_root) / "scripts" / "buildsystems" / "vcpkg.cmake" if args.build_wasm: @@ -1329,9 +1345,17 @@ def generate_build_tree( elif args.android: generate_android_triplets(build_dir, args.android_cpp_shared, args.android_api) elif is_windows(): - generate_windows_triplets(build_dir) + generate_windows_triplets(build_dir, args.msvc_toolset) + elif is_macOS(): + osx_target = args.apple_deploy_target + if args.apple_deploy_target is None: + osx_target = os.environ.get("MACOSX_DEPLOYMENT_TARGET") + if osx_target is not None: + log.info(f"Setting VCPKG_OSX_DEPLOYMENT_TARGET to {osx_target}") + generate_macos_triplets(build_dir, osx_target) else: - generate_posix_triplets(build_dir) + # Linux, *BSD, AIX or other platforms + generate_linux_triplets(build_dir) add_default_definition(cmake_extra_defines, "CMAKE_TOOLCHAIN_FILE", str(vcpkg_toolchain_path)) vcpkg_install_options = generate_vcpkg_install_options(build_dir, args) @@ -1362,7 +1386,7 @@ def generate_build_tree( target_arch = platform.machine() if args.arm64: target_arch = "ARM64" - elif args.arm64: + elif args.arm64ec: target_arch = "ARM64EC" cpu_arch = platform.architecture()[0] if target_arch == "AMD64": @@ -1414,6 +1438,12 @@ def generate_build_tree( cmake_args.append("-Donnxruntime_DNNL_ACL_ROOT=" + args.dnnl_acl_root) if args.build_wasm: cmake_args.append("-Donnxruntime_ENABLE_WEBASSEMBLY_SIMD=" + ("ON" if args.enable_wasm_simd else "OFF")) + if args.enable_wasm_relaxed_simd: + if not args.enable_wasm_simd: + raise BuildError( + "Wasm Relaxed SIMD (--enable_wasm_relaxed_simd) is only available with Wasm SIMD (--enable_wasm_simd)." + ) + cmake_args += ["-Donnxruntime_ENABLE_WEBASSEMBLY_RELAXED_SIMD=ON"] if args.use_migraphx: cmake_args.append("-Donnxruntime_MIGRAPHX_HOME=" + migraphx_home) if args.use_rocm: @@ -1502,7 +1532,7 @@ def generate_build_tree( ] # VitisAI and OpenVINO providers currently only support full_protobuf option. - if args.use_full_protobuf or args.use_openvino or args.use_vitisai or args.gen_doc: + if args.use_full_protobuf or args.use_openvino or args.use_vitisai or args.gen_doc or args.enable_generic_interface: cmake_args += ["-Donnxruntime_USE_FULL_PROTOBUF=ON", "-DProtobuf_USE_STATIC_LIBS=ON"] if args.use_cuda and not is_windows(): @@ -1592,8 +1622,11 @@ def generate_build_tree( raise BuildError("WebNN is only available for WebAssembly build.") cmake_args += ["-Donnxruntime_USE_WEBNN=ON"] - if args.use_jsep and args.use_webgpu: - raise BuildError("JSEP (--use_jsep) and WebGPU (--use_webgpu) cannot be enabled at the same time.") + # TODO: currently we allows building with both --use_jsep and --use_webgpu in this working branch. + # This situation is temporary. Eventually, those two flags will be mutually exclusive. + # + # if args.use_jsep and args.use_webgpu: + # raise BuildError("JSEP (--use_jsep) and WebGPU (--use_webgpu) cannot be enabled at the same time.") if args.use_external_dawn and not args.use_webgpu: raise BuildError("External Dawn (--use_external_dawn) must be enabled with WebGPU (--use_webgpu).") @@ -1606,12 +1639,14 @@ def generate_build_tree( if args.use_snpe: cmake_args += ["-Donnxruntime_USE_SNPE=ON"] - if args.macos or args.ios or args.visionos: + cmake_args += ["-Donnxruntime_USE_KLEIDIAI=" + ("OFF" if args.no_kleidiai else "ON")] + + if args.macos or args.ios or args.visionos or args.tvos: # Note: Xcode CMake generator doesn't have a good support for Mac Catalyst yet. if args.macos == "Catalyst" and args.cmake_generator == "Xcode": raise BuildError("Xcode CMake generator ('--cmake_generator Xcode') doesn't support Mac Catalyst build.") - if (args.ios or args.visionos or args.macos == "MacOSX") and not args.cmake_generator == "Xcode": + if (args.ios or args.visionos or args.tvos or args.macos == "MacOSX") and not args.cmake_generator == "Xcode": raise BuildError( "iOS/MacOS framework build requires use of the Xcode CMake generator ('--cmake_generator Xcode')." ) @@ -1671,6 +1706,16 @@ def generate_build_tree( ), "-Donnxruntime_ENABLE_CPUINFO=OFF", ] + if args.tvos: + cmake_args += [ + "-DCMAKE_SYSTEM_NAME=tvOS", + "-DCMAKE_TOOLCHAIN_FILE=" + + ( + args.tvos_toolchain_file + if args.tvos_toolchain_file + else "../cmake/onnxruntime_tvos.toolchain.cmake" + ), + ] if args.build_wasm: if not args.use_vcpkg: @@ -1941,7 +1986,7 @@ def generate_build_tree( ] env = {} if args.use_vcpkg: - env["VCPKG_KEEP_ENV_VARS"] = "TRT_UPLOAD_AUTH_TOKEN" + env["VCPKG_KEEP_ENV_VARS"] = "TRT_UPLOAD_AUTH_TOKEN;EMSDK;EMSDK_NODE;EMSDK_PYTHON" if args.build_wasm: env["EMSDK"] = emsdk_dir @@ -2396,6 +2441,8 @@ def run_onnxruntime_tests(args, source_dir, ctest_path, build_dir, configs): if args.use_cuda: log.info("Testing CUDA Graph feature") run_subprocess([sys.executable, "onnxruntime_test_python_cudagraph.py"], cwd=cwd, dll_path=dll_path) + log.info("Testing running inference concurrently") + run_subprocess([sys.executable, "onnxruntime_test_python_ort_parallel.py"], cwd=cwd, dll_path=dll_path) if args.use_dml: log.info("Testing DML Graph feature") @@ -2615,6 +2662,7 @@ def build_nuget_package( use_dnnl, use_winml, use_qnn, + use_dml, enable_training_apis, msbuild_extra_options, ): @@ -2657,6 +2705,8 @@ def build_nuget_package( package_name = "/p:OrtPackageId=Microsoft.ML.OnnxRuntime.DNNL" elif use_cuda: package_name = "/p:OrtPackageId=Microsoft.ML.OnnxRuntime.Gpu" + elif use_dml: + package_name = "/p:OrtPackageId=Microsoft.ML.OnnxRuntime.DirectML" elif use_rocm: package_name = "/p:OrtPackageId=Microsoft.ML.OnnxRuntime.ROCm" elif use_qnn: @@ -2773,21 +2823,21 @@ def run_csharp_tests( csharp_source_dir = os.path.join(source_dir, "csharp") # define macros based on build args - macros = "" + macros = [] if use_openvino: - macros += "USE_OPENVINO;" + macros.append("USE_OPENVINO") if use_tensorrt: - macros += "USE_TENSORRT;" + macros.append("USE_TENSORRT") if use_dnnl: - macros += "USE_DNNL;" + macros.append("USE_DNNL") if use_cuda: - macros += "USE_CUDA;" + macros.append("USE_CUDA") if enable_training_apis: - macros += "__TRAINING_ENABLED_NATIVE_BUILD__;__ENABLE_TRAINING_APIS__" + macros += ["__TRAINING_ENABLED_NATIVE_BUILD__", "__ENABLE_TRAINING_APIS__"] define_constants = "" if macros: - define_constants = '/p:DefineConstants="' + macros + '"' + define_constants = '/p:DefineConstants="' + ";".join(macros) + '"' # set build directory based on build_dir arg native_build_dir = os.path.normpath(os.path.join(source_dir, build_dir)) @@ -3133,7 +3183,7 @@ def main(): if is_macOS(): if ( - not (args.ios or args.visionos) + not (args.ios or args.visionos or args.tvos) and args.macos != "Catalyst" and not args.android and args.osx_arch == "arm64" @@ -3270,6 +3320,7 @@ def main(): args.use_dnnl, args.use_winml, args.use_qnn, + args.use_dml, args.enable_training_apis, normalize_arg_list(args.msbuild_extra_options), ) diff --git a/tools/ci_build/github/apple/default_full_ios_framework_build_settings.json b/tools/ci_build/github/apple/default_full_ios_framework_build_settings.json index 0fdc276ab5288..9658817d4409b 100644 --- a/tools/ci_build/github/apple/default_full_ios_framework_build_settings.json +++ b/tools/ci_build/github/apple/default_full_ios_framework_build_settings.json @@ -18,6 +18,7 @@ "--build_apple_framework", "--use_coreml", "--skip_tests", + "--no_kleidiai", "--cmake_extra_defines=onnxruntime_BUILD_UNIT_TESTS=OFF" ], "iphoneos": [ diff --git a/tools/ci_build/github/apple/default_full_tvos_framework_build_settings.json b/tools/ci_build/github/apple/default_full_tvos_framework_build_settings.json new file mode 100644 index 0000000000000..00f00f86f627c --- /dev/null +++ b/tools/ci_build/github/apple/default_full_tvos_framework_build_settings.json @@ -0,0 +1,30 @@ +{ + "build_osx_archs": { + "appletvos": [ + "arm64" + ], + "appletvsimulator": [ + "arm64", + "x86_64" + ] + }, + "build_params": { + "base": [ + "--parallel", + "--build_apple_framework", + "--use_coreml", + "--skip_tests", + "--cmake_extra_defines=onnxruntime_BUILD_UNIT_TESTS=OFF" + ], + "appletvos": [ + "--tvos", + "--use_xcode", + "--apple_deploy_target=15.1" + ], + "appletvsimulator": [ + "--tvos", + "--use_xcode", + "--apple_deploy_target=15.1" + ] + } +} diff --git a/tools/ci_build/github/azure-pipelines/android-arm64-v8a-QNN-crosscompile-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/android-arm64-v8a-QNN-crosscompile-ci-pipeline.yml index f403975f4efe6..18a14aa0ac075 100644 --- a/tools/ci_build/github/azure-pipelines/android-arm64-v8a-QNN-crosscompile-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/android-arm64-v8a-QNN-crosscompile-ci-pipeline.yml @@ -32,7 +32,7 @@ parameters: - name: QnnSdk displayName: QNN SDK version type: string - default: 2.31.0.250130 + default: 2.32.0.250228 jobs: - job: Build_QNN_EP diff --git a/tools/ci_build/github/azure-pipelines/android-x86_64-crosscompile-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/android-x86_64-crosscompile-ci-pipeline.yml deleted file mode 100644 index 3cceadd1b8ef5..0000000000000 --- a/tools/ci_build/github/azure-pipelines/android-x86_64-crosscompile-ci-pipeline.yml +++ /dev/null @@ -1,241 +0,0 @@ -##### start trigger Don't edit it manually, Please do edit set-trigger-rules.py #### -### please do rerun set-trigger-rules.py ### -trigger: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -pr: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -#### end trigger #### - -# Known Limits -# 1. Anchors are not supported in GHA -# https://github.community/t/support-for-yaml-anchors/16128/90 -# 2. today most cloud-based CI services are still lacking hardware acceleration support from the host VM, -# which is the no.1 blocker for running tests on modern Android Emulators (especially on recent API levels) on CI. - -# It'd better to check out https://github.com/microsoft/onnxruntime/wiki/Leverage-Existing-Artifacts -# to save debugging time. -parameters: -- name: specificArtifact - displayName: Use Specific Artifact - type: boolean - default: false -- name: runId - displayName: Specific Artifact's RunId - type: number - default: 0 - -stages: -# Separate stage for building CPU vs NNAPI as we only want CodeQL to run on one of them so we don't get duplicate -# issues for code that is built in both. We pick NNAPI as that includes the NNAPI EP code. -- stage: BUILD_AND_TEST_CPU - dependsOn: [] - variables: - Codeql.Enabled: false - ANDROID_AVD_HOME: $(Agent.TempDirectory) - jobs: - - job: BUILD_AND_TEST_CPU - pool: onnxruntime-Ubuntu2204-AMD-CPU - workspace: - clean: all - timeoutInMinutes: 30 - steps: - - task: JavaToolInstaller@0 - displayName: Use jdk 17 - inputs: - versionSpec: '17' - jdkArchitectureOption: 'x64' - jdkSourceOption: 'PreInstalled' - - - script: sudo apt-get update -y && sudo apt-get install -y coreutils ninja-build - displayName: Install coreutils and ninja - - - template: templates/use-android-ndk.yml - - template: templates/use-android-emulator.yml - parameters: - create: true - start: true - - script: | - env | grep ANDROID - displayName: View Android ENVs - - script: | - python3 tools/ci_build/build.py \ - --enable_lto \ - --android \ - --build_dir build \ - --android_sdk_path $ANDROID_HOME \ - --android_ndk_path $ANDROID_NDK_HOME \ - --android_abi=x86_64 \ - --android_api=30 \ - --skip_submodule_sync \ - --parallel --use_vcpkg --use_vcpkg_ms_internal_asset_cache \ - --cmake_generator=Ninja \ - --build_java - displayName: CPU EP, Build and Test - - template: templates/use-android-emulator.yml - parameters: - stop: true - - - template: templates/clean-agent-build-directory-step.yml - -- stage: BUILD_AND_TEST_NNAPI_EP - dependsOn: [] - condition: notIn(variables['Build.Reason'], 'IndividualCI', 'BatchedCI') - variables: - ANDROID_AVD_HOME: $(Agent.TempDirectory) - Codeql.ProjectConfigPath: .github/workflows - Codeql.Enabled: true - Codeql.Language: cpp - ${{ if variables['Codeql.Enabled'] }}: - JobsTimeout: 120 - ${{ else }}: - JobsTimeout: 60 - jobs: - - job: BUILD_AND_TEST_NNAPI_EP - pool: onnxruntime-Ubuntu2204-AMD-CPU - timeoutInMinutes: ${{ variables.JobsTimeout }} - workspace: - clean: all - steps: - - task: JavaToolInstaller@0 - displayName: Use jdk 17 - inputs: - versionSpec: '17' - jdkArchitectureOption: 'x64' - jdkSourceOption: 'PreInstalled' - - - script: sudo apt-get update -y && sudo apt-get install -y coreutils ninja-build - displayName: Install coreutils and ninja - - template: templates/use-android-emulator.yml - parameters: - create: true - start: true - - - script: | - env | grep ANDROID - displayName: View Android ENVs - - - script: | - python3 tools/ci_build/build.py \ - --enable_lto \ - --android \ - --build_dir build_nnapi \ - --android_sdk_path $ANDROID_HOME \ - --android_ndk_path $ANDROID_NDK_HOME \ - --android_abi=x86_64 \ - --android_api=29 \ - --skip_submodule_sync \ - --parallel --use_vcpkg --use_vcpkg_ms_internal_asset_cache \ - --use_nnapi \ - --build_shared_lib \ - --cmake_generator=Ninja \ - --build_java - displayName: NNAPI EP, Build, Test on Android Emulator - - - script: /bin/bash tools/ci_build/github/linux/ort_minimal/nnapi_minimal_build_minimal_ort_and_run_tests.sh $(pwd) - # Build Minimal ORT with NNAPI and reduced Ops, run unit tests on Android Emulator - displayName: Build Minimal ORT with NNAPI and run tests - - - template: templates/use-android-emulator.yml - parameters: - stop: true - - - template: templates/clean-agent-build-directory-step.yml - -- stage: MAIN_BUILD_STAGE - # The below jobs only run on build of main branch. - # because coverage report is hard to support in cross machines. - displayName: NNAPI MAIN BUILD&TEST - dependsOn: [] - condition: in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI') - variables: - ANDROID_AVD_HOME: $(Agent.TempDirectory) - jobs: - - job: NNAPI_EP_MASTER - pool: onnxruntime-Ubuntu2204-AMD-CPU - timeoutInMinutes: 180 - workspace: - clean: all - condition: in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI') - steps: - - task: JavaToolInstaller@0 - displayName: Use jdk 17 - inputs: - versionSpec: '17' - jdkArchitectureOption: 'x64' - jdkSourceOption: 'PreInstalled' - - - template: templates/use-android-ndk.yml - - - template: templates/use-android-emulator.yml - parameters: - create: true - start: true - - - script: | - python3 tools/ci_build/build.py \ - --enable_lto \ - --android \ - --build_dir build_nnapi \ - --android_sdk_path $ANDROID_HOME \ - --android_ndk_path $ANDROID_NDK_HOME \ - --android_abi=x86_64 \ - --android_api=29 \ - --skip_submodule_sync \ - --parallel --use_vcpkg --use_vcpkg_ms_internal_asset_cache \ - --use_nnapi \ - --build_shared_lib \ - --cmake_generator=Ninja \ - --build_java \ - --code_coverage - displayName: NNAPI EP, Build, Test, CodeCoverage on Android Emulator - - # We need to use llvm-cov from the NDK. - - script: | - export GCOV="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-cov gcov" - python3 -m pip install gcovr - python3 tools/ci_build/coverage.py --build_dir build_nnapi --android_sdk_path $ANDROID_HOME - displayName: Retrieve runtime code coverage files from the emulator and analyze - - - script: cat '$(Build.SourcesDirectory)/build_nnapi/Debug/coverage_rpt.txt' - displayName: Print coverage report - - # - task: AzureCLI@2 - # displayName: 'Post Android Code Coverage To DashBoard' - # inputs: - # azureSubscription: AIInfraBuild - # scriptType: bash - # scriptPath: $(Build.SourcesDirectory)/tools/ci_build/github/linux/upload_code_coverage_data.sh - # arguments: '"$(Build.SourcesDirectory)/build_nnapi/Debug/coverage_rpt.txt" "https://dev.azure.com/onnxruntime/onnxruntime/_build/results?buildId=$(Build.BuildId)" arm android nnapi' - # workingDirectory: '$(Build.BinariesDirectory)' - - - script: /bin/bash tools/ci_build/github/linux/ort_minimal/nnapi_minimal_build_minimal_ort_and_run_tests.sh $(pwd) - # Build Minimal ORT with NNAPI and reduced Ops, run unit tests on Android Emulator - displayName: Build Minimal ORT with NNAPI and run tests - - - template: templates/use-android-emulator.yml - parameters: - stop: true - - - template: templates/clean-agent-build-directory-step.yml diff --git a/tools/ci_build/github/azure-pipelines/bigmodels-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/bigmodels-ci-pipeline.yml index 7b96a50195a06..f4658f3a22c33 100644 --- a/tools/ci_build/github/azure-pipelines/bigmodels-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/bigmodels-ci-pipeline.yml @@ -41,11 +41,11 @@ parameters: variables: - name: docker_base_image - value: onnxruntimebuildcache.azurecr.io/internal/azureml/onnxruntime/build/cuda11_x64_almalinux8_gcc11:20250124.1 + value: onnxruntimebuildcache.azurecr.io/internal/azureml/onnxruntime/build/cuda12_x64_ubi8_gcc12:20250124.1 - name: linux_trt_version - value: 10.3.0.26-1.cuda11.8 + value: 10.9.0.34-1.cuda12.8 - name: Repository - value: 'onnxruntimecuda11manylinuxbuild' + value: 'onnxruntimecuda12manylinuxbuild' stages: - stage: Build_Onnxruntime_Cuda @@ -93,6 +93,7 @@ stages: $(Repository) \ /bin/bash -c ' set -ex; \ + ls /usr/local/; \ PATH=/opt/python/cp310-cp310/bin:$PATH /opt/python/cp310-cp310/bin/python3 /onnxruntime_src/tools/ci_build/build.py \ --build_dir /build --cmake_generator Ninja \ --config Release --update --build \ @@ -100,9 +101,9 @@ stages: --build_shared_lib \ --parallel --use_vcpkg --use_vcpkg_ms_internal_asset_cache \ --build_wheel \ - --enable_onnx_tests --use_cuda --cuda_version=11.8 --cuda_home=/usr/local/cuda-11.8 --cudnn_home=/usr/local/cuda-11.8 \ + --enable_onnx_tests --use_cuda --cuda_version=12.2 --cuda_home=/usr/local/cuda-12.2 --cudnn_home=/usr/local/cuda-12.2 \ --enable_cuda_profiling \ - --enable_pybind --build_java \ + --enable_pybind \ --cmake_extra_defines "CMAKE_CUDA_ARCHITECTURES=75;86" ' workingDirectory: $(Build.SourcesDirectory) @@ -164,7 +165,7 @@ stages: DockerBuildArgs: " --build-arg BUILD_UID=$( id -u ) " - Repository: onnxruntimeubuntupackagestest_cuda11 + Repository: onnxruntimeubuntupackagestest_cuda12 UseImageCacheContainerRegistry: false - task: Cache@2 @@ -182,14 +183,14 @@ stages: -v $(Build.BinariesDirectory)/Release:/Release \ -v $(STABLE_DIFFUSION_MODEL_CACHE):/model_cache:rw \ -v $(GenerateImage_DIR):/images:rw \ - onnxruntimeubuntupackagestest_cuda11 \ + onnxruntimeubuntupackagestest_cuda12 \ bash -c ' \ set -ex; \ python3 --version; \ python3 -m pip install --upgrade pip; \ python3 -m pip install /Release/*.whl; \ pushd /workspace/onnxruntime/python/tools/transformers/models/stable_diffusion; \ - python3 -m pip install -r requirements/cuda11/requirements.txt; \ + python3 -m pip install -r requirements/cuda12/requirements.txt; \ python3 -m pip install numpy==1.22.2; \ python3 -m pip install --upgrade polygraphy onnx-graphsurgeon ; \ echo Generate an image guided by a text prompt; \ @@ -221,7 +222,7 @@ stages: - script: | docker run -e SYSTEM_COLLECTIONURI --rm --gpus all -v $PWD:/workspace \ -v $(CLIP_MODEL_CACHE):/model_cache:rw \ - onnxruntimeubuntupackagestest_cuda11 \ + onnxruntimeubuntupackagestest_cuda12 \ bash -c ' set -x; \ python3 --version; \ @@ -248,7 +249,7 @@ stages: - script: | docker run -e SYSTEM_COLLECTIONURI --rm --gpus all -v $PWD:/workspace \ -v $(CLIP_MODEL_CACHE):/model_cache:rw \ - onnxruntimeubuntupackagestest_cuda11 \ + onnxruntimeubuntupackagestest_cuda12 \ bash -c ' set -ex; \ python3 --version; \ @@ -434,6 +435,49 @@ stages: - script: | docker run -e SYSTEM_COLLECTIONURI --rm --gpus all -v $(Build.SourcesDirectory):/workspace \ + -v $(Build.BinariesDirectory)/ort-artifact/:/ort-artifact \ + onnxruntimepackagestest_ompffmpeg \ + bash -c ' + set -ex; \ + pushd /workspace/onnxruntime/python/tools/transformers/ ; \ + python3 -m pip install --upgrade pip ; \ + pushd models/whisper ; \ + python3 -m pip install -r requirements.txt ; \ + popd ; \ + python3 -m pip install /ort-artifact/*.whl ; \ + python3 -m pip uninstall -y torch ; \ + python3 -m pip install torch --index-url https://download.pytorch.org/whl/cu124 ; \ + python3 -m models.whisper.convert_to_onnx -m openai/whisper-tiny --output wtiny-fp32-cpu-hf --precision fp32 --provider cpu --overwrite --use_external_data_format --optimize_onnx --no_beam_search_op --output_cross_qk ; \ + python3 -m models.whisper.convert_to_onnx -m openai/whisper-tiny --output wtiny-fp32-cpu-hf --precision fp32 --provider cpu --overwrite --use_external_data_format --optimize_onnx ; \ + python3 -m models.whisper.convert_to_onnx -m openai/whisper-tiny --output wtiny-fp32-cpu-hf --precision fp32 --provider cpu --overwrite --use_external_data_format --optimize_onnx --no_beam_search_op --output_cross_qk --separate_encoder_and_decoder_init ; \ + rm -rf wtiny-fp32-cpu-hf ; \ + python3 -m models.whisper.convert_to_onnx -m openai/whisper-tiny --model_impl openai --output wtiny-fp32-cpu-oai --precision fp32 --provider cpu --overwrite --use_external_data_format --optimize_onnx --no_beam_search_op --output_cross_qk ; \ + python3 -m models.whisper.convert_to_onnx -m openai/whisper-tiny --model_impl openai --output wtiny-fp32-cpu-oai --precision fp32 --provider cpu --overwrite --use_external_data_format --optimize_onnx ; \ + python3 -m models.whisper.convert_to_onnx -m openai/whisper-tiny --model_impl openai --output wtiny-fp32-cpu-oai --precision fp32 --provider cpu --overwrite --use_external_data_format --optimize_onnx --no_beam_search_op --output_cross_qk --separate_encoder_and_decoder_init ; \ + rm -rf wtiny-fp32-cpu-oai ; \ + python3 -m models.whisper.convert_to_onnx -m openai/whisper-tiny --output wtiny-fp32-cuda-hf --precision fp32 --provider cuda --use_gpu --overwrite --use_external_data_format --optimize_onnx --no_beam_search_op --output_cross_qk ; \ + python3 -m models.whisper.convert_to_onnx -m openai/whisper-tiny --output wtiny-fp32-cuda-hf --precision fp32 --provider cuda --use_gpu --overwrite --use_external_data_format --optimize_onnx --output_cross_qk ; \ + python3 -m models.whisper.convert_to_onnx -m openai/whisper-tiny --output wtiny-fp32-cuda-hf --precision fp32 --provider cuda --use_gpu --overwrite --use_external_data_format --optimize_onnx --no_beam_search_op --output_cross_qk --separate_encoder_and_decoder_init ; \ + rm -rf wtiny-fp32-cuda-hf ; \ + python3 -m models.whisper.convert_to_onnx -m openai/whisper-tiny --model_impl openai --output wtiny-fp32-cuda-oai --precision fp32 --provider cuda --use_gpu --overwrite --use_external_data_format --optimize_onnx --no_beam_search_op --output_cross_qk ; \ + python3 -m models.whisper.convert_to_onnx -m openai/whisper-tiny --model_impl openai --output wtiny-fp32-cuda-oai --precision fp32 --provider cuda --use_gpu --overwrite --use_external_data_format --optimize_onnx --output_cross_qk ; \ + python3 -m models.whisper.convert_to_onnx -m openai/whisper-tiny --model_impl openai --output wtiny-fp32-cuda-oai --precision fp32 --provider cuda --use_gpu --overwrite --use_external_data_format --optimize_onnx --no_beam_search_op --output_cross_qk --separate_encoder_and_decoder_init ; \ + rm -rf wtiny-fp32-cuda-oai ; \ + python3 -m models.whisper.convert_to_onnx -m openai/whisper-tiny --output wtiny-fp16-cuda-hf --precision fp16 --provider cuda --use_gpu --overwrite --use_external_data_format --optimize_onnx --no_beam_search_op --output_cross_qk ; \ + python3 -m models.whisper.convert_to_onnx -m openai/whisper-tiny --output wtiny-fp16-cuda-hf --precision fp16 --provider cuda --use_gpu --overwrite --use_external_data_format --optimize_onnx --no_beam_search_op --output_cross_qk --separate_encoder_and_decoder_init ; \ + python3 -m models.whisper.convert_to_onnx -m openai/whisper-tiny --output wtiny-fp16-cuda-hf --precision fp16 --provider cuda --use_gpu --overwrite --use_external_data_format --optimize_onnx --collect_cross_qk --output_cross_qk --use_forced_decoder_ids ; \ + rm -rf wtiny-fp16-cuda-hf ; \ + python3 -m models.whisper.convert_to_onnx -m openai/whisper-tiny --model_impl openai --output wtiny-fp16-cuda-oai --precision fp16 --provider cuda --use_gpu --overwrite --use_external_data_format --optimize_onnx --no_beam_search_op --output_cross_qk ; \ + python3 -m models.whisper.convert_to_onnx -m openai/whisper-tiny --model_impl openai --output wtiny-fp16-cuda-oai --precision fp16 --provider cuda --use_gpu --overwrite --use_external_data_format --optimize_onnx --no_beam_search_op --output_cross_qk --separate_encoder_and_decoder_init ; \ + python3 -m models.whisper.convert_to_onnx -m openai/whisper-tiny --model_impl openai --output wtiny-fp16-cuda-oai --precision fp16 --provider cuda --use_gpu --overwrite --use_external_data_format --optimize_onnx --collect_cross_qk --output_cross_qk --use_forced_decoder_ids ; \ + rm -rf wtiny-fp16-cuda-oai ; \ + popd ; \ + ' + displayName: 'Test Whisper export flag combinations' + workingDirectory: $(Build.SourcesDirectory) + + - script: | + docker run --rm --gpus all -v $(Build.SourcesDirectory):/workspace \ -v $(Build.BinariesDirectory)/ort-artifact/:/ort-artifact \ -v $(Agent.TempDirectory)/whisper_large_v3:/whisper_large_v3 \ onnxruntimepackagestest_ompffmpeg \ @@ -446,7 +490,7 @@ stages: popd ; \ python3 -m pip install /ort-artifact/*.whl ; \ python3 -m pip uninstall -y torch ; \ - python3 -m pip install torch --index-url https://download.pytorch.org/whl/cu118 ; \ + python3 -m pip install torch --index-url https://download.pytorch.org/whl/cu124 ; \ python3 -m models.whisper.convert_to_onnx -m /whisper_large_v3 --output whisperlargev3 --use_external_data_format ; \ popd ; \ ' @@ -467,7 +511,7 @@ stages: popd ; \ python3 -m pip install /ort-artifact/*.whl ; \ python3 -m pip uninstall -y torch ; \ - python3 -m pip install torch --index-url https://download.pytorch.org/whl/cu118 ; \ + python3 -m pip install torch --index-url https://download.pytorch.org/whl/cu124 ; \ ls whisperlargev3; \ export LD_LIBRARY_PATH=/tmp/ompffmpeg:${LD_LIBRARY_PATH}; \ ffmpeg -version; \ diff --git a/tools/ci_build/github/azure-pipelines/c-api-noopenmp-packaging-pipelines.yml b/tools/ci_build/github/azure-pipelines/c-api-noopenmp-packaging-pipelines.yml index 543b2cfd19894..8f1189b05858c 100644 --- a/tools/ci_build/github/azure-pipelines/c-api-noopenmp-packaging-pipelines.yml +++ b/tools/ci_build/github/azure-pipelines/c-api-noopenmp-packaging-pipelines.yml @@ -9,11 +9,6 @@ parameters: type: boolean default: false -- name: DoCompliance - displayName: Run Compliance Tasks? - type: boolean - default: true - - name: DoEsrp displayName: Run code sign tasks? Must be true if you are doing an ONNX Runtime release type: boolean @@ -62,7 +57,7 @@ parameters: - name: QnnSdk displayName: QNN SDK Version type: string - default: 2.31.0.250130 + default: 2.32.0.250228 resources: repositories: @@ -70,222 +65,176 @@ resources: type: github endpoint: ort-examples name: microsoft/onnxruntime-inference-examples + - repository: 1esPipelines + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release variables: - template: templates/common-variables.yml - name: ReleaseVersionSuffix value: '' - name: win_trt_version - value: 11.8 + value: 12.2 - name: win_trt_home - value: $(Agent.TempDirectory)\${{ variables.win_trt_folder_cuda11 }} + value: $(Agent.TempDirectory)\${{ variables.win_trt_folder_cuda12 }} - name: win_cuda_home - value: $(Agent.TempDirectory)\v11.8 - -stages: -- template: stages/set_packaging_variables_stage.yml - parameters: - IsReleaseBuild: ${{ parameters.IsReleaseBuild }} - PreReleaseVersionSuffixString: ${{ parameters.PreReleaseVersionSuffixString }} - PreReleaseVersionSuffixNumber: ${{ parameters.PreReleaseVersionSuffixNumber }} - -- template: stages/download-java-tools-stage.yml - -- template: templates/c-api-cpu.yml - parameters: - RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - DoCompliance: ${{ parameters.DoCompliance }} - DoEsrp: ${{ parameters.DoEsrp }} - IsReleaseBuild: ${{ parameters.IsReleaseBuild }} - ${{ if eq(parameters.NugetPackageSuffix, 'NONE') }}: - OrtNugetPackageId: 'Microsoft.ML.OnnxRuntime' - ${{ else }}: - OrtNugetPackageId: 'Microsoft.ML.OnnxRuntime${{ parameters.NugetPackageSuffix }}' - AdditionalBuildFlags: '' - AdditionalWinBuildFlags: '--enable_onnx_tests --enable_wcos ${{parameters.AdditionalBuildFlag}}' - BuildVariant: 'default' - SpecificArtifact: ${{ parameters.SpecificArtifact }} - BuildId: ${{ parameters.BuildId }} - QnnSDKVersion: ${{ parameters.QnnSdk }} - -- template: stages/java-cuda-packaging-stage.yml - parameters: - CudaVersion: 11.8 - SpecificArtifact: ${{ parameters.SpecificArtifact }} - BuildId: ${{ parameters.BuildId }} - -- template: stages/nuget-combine-cuda-stage.yml - parameters: - DoCompliance: ${{ parameters.DoCompliance }} - CudaVersion: 11.8 - RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - UseIncreasedTimeoutForTests: ${{ parameters.UseIncreasedTimeoutForTests }} - win_trt_home: ${{ variables.win_trt_home }} - win_cuda_home: ${{ variables.win_cuda_home }} - DoEsrp: ${{ parameters.DoEsrp }} - IsReleaseBuild: ${{ parameters.IsReleaseBuild }} - buildJava: true - buildNodejs: true - SpecificArtifact: ${{ parameters.SpecificArtifact }} - BuildId: ${{ parameters.BuildId }} - - -- template: nuget/templates/dml-vs-2022.yml - parameters: - IsReleaseBuild: ${{ parameters.IsReleaseBuild }} - ArtifactName: 'drop-nuget-dml' - StageName: 'Windows_CI_GPU_DML_Dev' - BuildCommand: --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --enable_onnx_tests --enable_wcos --use_telemetry --use_dml --build_nodejs --cmake_generator "Visual Studio 17 2022" --use_vcpkg --use_vcpkg_ms_internal_asset_cache - BuildArch: 'x64' - msbuildArchitecture: 'amd64' - EnvSetupScript: 'setup_env.bat' - sln_platform: 'x64' - DoDebugBuild: 'false' - DoNugetPack: 'true' - DoCompliance: 'false' - DoEsrp: ${{ parameters.DoEsrp }} - NuPackScript: | - msbuild $(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.proj /p:Configuration=RelWithDebInfo /t:CreatePackage /p:OrtPackageId=Microsoft.ML.OnnxRuntime.DirectML /p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} /p:CurrentData=$(BuildDate) /p:CurrentTime=$(BuildTime) - copy $(Build.SourcesDirectory)\csharp\src\Microsoft.ML.OnnxRuntime\bin\RelWithDebInfo\*.nupkg $(Build.ArtifactStagingDirectory) - copy $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\*.nupkg $(Build.ArtifactStagingDirectory) - mkdir $(Build.ArtifactStagingDirectory)\testdata - copy $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\custom_op_library.* $(Build.ArtifactStagingDirectory)\testdata - -- template: nuget/templates/dml-vs-2022.yml - parameters: - IsReleaseBuild: ${{ parameters.IsReleaseBuild }} - ArtifactName: 'drop-win-dml-x86-zip' - StageName: 'Windows_CI_GPU_DML_Dev_x86' - BuildCommand: --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --enable_onnx_tests --enable_wcos --use_telemetry --use_dml --cmake_generator "Visual Studio 17 2022" --use_vcpkg --use_vcpkg_ms_internal_asset_cache - BuildArch: 'x86' - EnvSetupScript: 'setup_env_x86.bat' - sln_platform: 'Win32' - DoDebugBuild: 'false' - DoNugetPack: 'true' - DoCompliance: ${{ parameters.DoCompliance }} - DoEsrp: ${{ parameters.DoEsrp }} - RunTests: 'false' - NuPackScript: | - msbuild $(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.proj /p:Configuration=RelWithDebInfo /p:TargetArchitecture=x86 /t:CreatePackage /p:OrtPackageId=Microsoft.ML.OnnxRuntime.DirectML /p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} - cd $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\ - ren Microsoft.ML.OnnxRuntime.DirectML.* win-dml-x86.zip - copy $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\win-dml-x86.zip $(Build.ArtifactStagingDirectory) - mkdir $(Build.ArtifactStagingDirectory)\testdata - copy $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\custom_op_library.* $(Build.ArtifactStagingDirectory)\testdata - -- template: nuget/templates/dml-vs-2022.yml + value: $(Agent.TempDirectory)\v12.2 +extends: + # The pipeline extends the 1ES PT which will inject different SDL and compliance tasks. + # For non-production pipelines, use "Unofficial" as defined below. + # For productions pipelines, use "Official". + template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines parameters: - IsReleaseBuild: ${{ parameters.IsReleaseBuild }} - ArtifactName: 'drop-win-dml-arm64-zip' - StageName: 'Windows_CI_GPU_DML_Dev_arm64' - BuildCommand: --build_dir $(Build.BinariesDirectory) --arm64 --skip_submodule_sync --build_shared_lib --enable_onnx_tests --enable_wcos --use_telemetry --use_dml --build_nodejs --cmake_generator "Visual Studio 17 2022" --use_vcpkg --use_vcpkg_ms_internal_asset_cache - BuildArch: 'x64' - EnvSetupScript: 'setup_env.bat' - sln_platform: 'arm64' - DoDebugBuild: 'false' - DoNugetPack: 'true' - DoCompliance: ${{ parameters.DoCompliance }} - DoEsrp: ${{ parameters.DoEsrp }} - RunTests: 'false' - NuPackScript: | - msbuild $(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.proj /p:Configuration=RelWithDebInfo /p:TargetArchitecture=arm64 /t:CreatePackage /p:OrtPackageId=Microsoft.ML.OnnxRuntime.DirectML /p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} - cd $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\ - ren Microsoft.ML.OnnxRuntime.DirectML.* win-dml-arm64.zip - copy $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\win-dml-arm64.zip $(Build.ArtifactStagingDirectory) - mkdir $(Build.ArtifactStagingDirectory)\testdata - copy $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\custom_op_library.* $(Build.ArtifactStagingDirectory)\testdata - -- stage: NuGet_Packaging_DML - dependsOn: - - Windows_CI_GPU_DML_Dev - - Windows_CI_GPU_DML_Dev_x86 - - Windows_CI_GPU_DML_Dev_arm64 - condition: succeeded() - jobs: - - job: NuGet_Packaging_DML - workspace: - clean: all - pool: 'onnxruntime-Win2022-GPU-dml-A10' - steps: - - task: DownloadPipelineArtifact@0 - displayName: 'Download Pipeline Artifact - NuGet DirectML' - inputs: - artifactName: 'drop-nuget-dml' - targetPath: '$(Build.BinariesDirectory)/nuget-artifact-dml' - - - task: DownloadPipelineArtifact@0 - displayName: 'Download Pipeline Artifact - NuGet DirectML x86' - inputs: - artifactName: 'drop-win-dml-x86-zip' - targetPath: '$(Build.BinariesDirectory)/nuget-artifact-dml' - - - task: DownloadPipelineArtifact@0 - displayName: 'Download Pipeline Artifact - NuGet DirectML arm64' - inputs: - artifactName: 'drop-win-dml-arm64-zip' - targetPath: '$(Build.BinariesDirectory)/nuget-artifact-dml' - - - script: | - pushd $(Build.BinariesDirectory)\nuget-artifact-dml - dir - powershell -Command "Invoke-WebRequest http://stahlworks.com/dev/unzip.exe -OutFile unzip.exe" - powershell -Command "Invoke-WebRequest http://stahlworks.com/dev/zip.exe -OutFile zip.exe" - set PATH=%CD%;%PATH% - SETLOCAL EnableDelayedExpansion - FOR /R %%i IN (*.nupkg) do ( - set filename=%%~ni - IF NOT "!filename:~25,7!"=="Managed" ( - rename %%~ni.nupkg %%~ni.zip - unzip %%~ni.zip -d %%~ni - del /Q %%~ni.zip - - unzip win-dml-x86.zip -d win-x86 - mkdir %%~ni\runtimes\win-x86 - mkdir %%~ni\runtimes\win-x86\native - - move win-x86\runtimes\win-x86\native\onnxruntime.dll %%~ni\runtimes\win-x86\native\onnxruntime.dll - move win-x86\runtimes\win-x86\native\onnxruntime.lib %%~ni\runtimes\win-x86\native\onnxruntime.lib - move win-x86\runtimes\win-x86\native\onnxruntime.pdb %%~ni\runtimes\win-x86\native\onnxruntime.pdb + sdl: + binskim: + enabled: true + analyzeTargetGlob: $(Build.ArtifactStagingDirectory)/**.dll + sourceAnalysisPool: "Onnxruntime-Win-CPU-2022" + componentgovernance: + ignoreDirectories: $(Build.SourcesDirectory)/onnxruntime-inference-examples + sourceRepositoriesToScan: + exclude: + - repository: onnxruntime-inference-examples + spotBugs: + enabled: false + justificationForDisabling: "Getting ##[error]1. SpotBugs Error gdn.unknownFormatResult - File: spotbugs.xml, which indicates that SpotBugs found one or more errors, which are not handled by the Guardian right now." + + stages: + - template: stages/set_packaging_variables_stage.yml + parameters: + IsReleaseBuild: ${{ parameters.IsReleaseBuild }} + PreReleaseVersionSuffixString: ${{ parameters.PreReleaseVersionSuffixString }} + PreReleaseVersionSuffixNumber: ${{ parameters.PreReleaseVersionSuffixNumber }} - unzip win-dml-arm64.zip -d win-arm64 - mkdir %%~ni\runtimes\win-arm64 - mkdir %%~ni\runtimes\win-arm64\native + - template: stages/download-java-tools-stage.yml - move win-arm64\runtimes\win-arm64\native\onnxruntime.dll %%~ni\runtimes\win-arm64\native\onnxruntime.dll - move win-arm64\runtimes\win-arm64\native\onnxruntime.lib %%~ni\runtimes\win-arm64\native\onnxruntime.lib - move win-arm64\runtimes\win-arm64\native\onnxruntime.pdb %%~ni\runtimes\win-arm64\native\onnxruntime.pdb + - template: templates/c-api-cpu.yml + parameters: + RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} + DoEsrp: ${{ parameters.DoEsrp }} + IsReleaseBuild: ${{ parameters.IsReleaseBuild }} + ${{ if eq(parameters.NugetPackageSuffix, 'NONE') }}: + OrtNugetPackageId: 'Microsoft.ML.OnnxRuntime' + ${{ else }}: + OrtNugetPackageId: 'Microsoft.ML.OnnxRuntime${{ parameters.NugetPackageSuffix }}' + AdditionalBuildFlags: '' + AdditionalWinBuildFlags: '--enable_onnx_tests --enable_wcos ${{parameters.AdditionalBuildFlag}}' + BuildVariant: 'default' + SpecificArtifact: ${{ parameters.SpecificArtifact }} + BuildId: ${{ parameters.BuildId }} + QnnSDKVersion: ${{ parameters.QnnSdk }} + is1ES: true + + - template: stages/java-cuda-packaging-stage.yml + parameters: + CudaVersion: 12.2 + SpecificArtifact: ${{ parameters.SpecificArtifact }} + BuildId: ${{ parameters.BuildId }} + - template: stages/nuget-combine-cuda-stage.yml + parameters: + CudaVersion: 12.2 + RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} + UseIncreasedTimeoutForTests: ${{ parameters.UseIncreasedTimeoutForTests }} + win_trt_home: ${{ variables.win_trt_home }} + win_cuda_home: ${{ variables.win_cuda_home }} + DoEsrp: ${{ parameters.DoEsrp }} + IsReleaseBuild: ${{ parameters.IsReleaseBuild }} + buildJava: true + buildNodejs: true + SpecificArtifact: ${{ parameters.SpecificArtifact }} + BuildId: ${{ parameters.BuildId }} - pushd %%~ni - zip -r ..\%%~ni.zip . - popd - move %%~ni.zip %%~ni.nupkg - ) - ) - popd - copy $(Build.BinariesDirectory)\nuget-artifact-dml\Microsoft.ML.OnnxRuntime.DirectML*nupkg $(Build.ArtifactStagingDirectory) - displayName: 'Bundle DML NuGet and other binaries' + - template: stages/nodejs-win-packaging-stage.yml + parameters: + IsReleaseBuild: ${{ parameters.IsReleaseBuild }} + ArtifactName: 'drop-onnxruntime-nodejs-win-x64' + StageName: 'Windows_Nodejs_Packaging_x64' + BuildCommand: --skip_submodule_sync --build_shared_lib --enable_onnx_tests --enable_wcos --use_telemetry --use_dml --use_webgpu --build_nodejs --cmake_generator "Visual Studio 17 2022" + BuildArch: 'x64' + EnvSetupScript: 'setup_env.bat' + sln_platform: 'x64' + DoEsrp: ${{ parameters.DoEsrp }} + PublishWebGpuBuildTools: true - - template: templates/esrp_nuget.yml + - template: stages/nodejs-win-packaging-stage.yml parameters: - DisplayName: 'ESRP - sign NuGet package' - FolderPath: '$(Build.ArtifactStagingDirectory)' + IsReleaseBuild: ${{ parameters.IsReleaseBuild }} + ArtifactName: 'drop-onnxruntime-nodejs-win-arm64' + StageName: 'Windows_Nodejs_Packaging_arm64' + BuildCommand: --arm64 --skip_submodule_sync --build_shared_lib --enable_onnx_tests --enable_wcos --use_telemetry --use_dml --use_webgpu --build_nodejs --cmake_generator "Visual Studio 17 2022" + BuildArch: 'x64' + EnvSetupScript: 'setup_env.bat' + sln_platform: 'arm64' DoEsrp: ${{ parameters.DoEsrp }} + DependsOnStageName: Windows_Nodejs_Packaging_x64 - - template: templates/validate-package.yml + - template: nuget/templates/dml-vs-2022.yml + parameters: + IsReleaseBuild: ${{ parameters.IsReleaseBuild }} + ArtifactName: 'drop-nuget-dml' + StageName: 'Windows_CI_GPU_DML_Dev' + BuildCommand: --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --enable_onnx_tests --enable_wcos --use_telemetry --use_dml --build_nodejs --cmake_generator "Visual Studio 17 2022" --use_vcpkg --use_vcpkg_ms_internal_asset_cache + BuildArch: 'x64' + msbuildArchitecture: 'amd64' + EnvSetupScript: 'setup_env.bat' + sln_platform: 'x64' + DoDebugBuild: 'false' + DoNugetPack: 'true' + DoEsrp: ${{ parameters.DoEsrp }} + NuPackScript: | + msbuild $(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.proj /p:Configuration=RelWithDebInfo /t:CreatePackage /p:OrtPackageId=Microsoft.ML.OnnxRuntime.DirectML /p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} /p:CurrentData=$(BuildDate) /p:CurrentTime=$(BuildTime) + copy $(Build.SourcesDirectory)\csharp\src\Microsoft.ML.OnnxRuntime\bin\RelWithDebInfo\*.nupkg $(Build.ArtifactStagingDirectory) + copy $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\*.nupkg $(Build.ArtifactStagingDirectory) + mkdir $(Build.ArtifactStagingDirectory)\testdata + copy $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\custom_op_library.* $(Build.ArtifactStagingDirectory)\testdata + + - template: nuget/templates/dml-vs-2022.yml + parameters: + IsReleaseBuild: ${{ parameters.IsReleaseBuild }} + ArtifactName: 'drop-win-dml-x86-zip' + StageName: 'Windows_CI_GPU_DML_Dev_x86' + BuildCommand: --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --enable_onnx_tests --enable_wcos --use_telemetry --use_dml --cmake_generator "Visual Studio 17 2022" --use_vcpkg --use_vcpkg_ms_internal_asset_cache + BuildArch: 'x86' + EnvSetupScript: 'setup_env_x86.bat' + sln_platform: 'Win32' + DoDebugBuild: 'false' + DoNugetPack: 'true' + DoEsrp: ${{ parameters.DoEsrp }} + RunTests: 'false' + NuPackScript: | + msbuild $(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.proj /p:Configuration=RelWithDebInfo /p:TargetArchitecture=x86 /t:CreatePackage /p:OrtPackageId=Microsoft.ML.OnnxRuntime.DirectML /p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} + cd $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\ + ren Microsoft.ML.OnnxRuntime.DirectML.* win-dml-x86.zip + copy $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\win-dml-x86.zip $(Build.ArtifactStagingDirectory) + mkdir $(Build.ArtifactStagingDirectory)\testdata + copy $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\custom_op_library.* $(Build.ArtifactStagingDirectory)\testdata + + - template: nuget/templates/dml-vs-2022.yml parameters: - PackageType: 'nuget' - PackagePath: '$(Build.ArtifactStagingDirectory)' - PackageName: 'Microsoft.ML.OnnxRuntime.DirectML*nupkg' - PlatformsSupported: 'win-x64,win-x86,win-arm64' - VerifyNugetSigning: ${{ parameters.DoEsrp }} + IsReleaseBuild: ${{ parameters.IsReleaseBuild }} + ArtifactName: 'drop-win-dml-arm64-zip' + StageName: 'Windows_CI_GPU_DML_Dev_arm64' + BuildCommand: --build_dir $(Build.BinariesDirectory) --arm64 --skip_submodule_sync --build_shared_lib --enable_onnx_tests --enable_wcos --use_telemetry --use_dml --build_nodejs --cmake_generator "Visual Studio 17 2022" --use_vcpkg --use_vcpkg_ms_internal_asset_cache + BuildArch: 'x64' + EnvSetupScript: 'setup_env.bat' + sln_platform: 'arm64' + DoDebugBuild: 'false' + DoNugetPack: 'true' + DoEsrp: ${{ parameters.DoEsrp }} + RunTests: 'false' + NuPackScript: | + msbuild $(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.proj /p:Configuration=RelWithDebInfo /p:TargetArchitecture=arm64 /t:CreatePackage /p:OrtPackageId=Microsoft.ML.OnnxRuntime.DirectML /p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} + cd $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\ + ren Microsoft.ML.OnnxRuntime.DirectML.* win-dml-arm64.zip + copy $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\win-dml-arm64.zip $(Build.ArtifactStagingDirectory) + mkdir $(Build.ArtifactStagingDirectory)\testdata + copy $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\custom_op_library.* $(Build.ArtifactStagingDirectory)\testdata + - - task: PublishPipelineArtifact@0 - displayName: 'Publish Pipeline NuGet Artifact' - inputs: - artifactName: 'drop-signed-nuget-dml' - targetPath: '$(Build.ArtifactStagingDirectory)' - - template: templates/component-governance-component-detection-steps.yml + + - template: stages/nuget_dml_packaging_stage.yml parameters: - condition: 'succeeded' + DoEsrp: ${{ parameters.DoEsrp }} diff --git a/tools/ci_build/github/azure-pipelines/cuda-packaging-pipeline.yml b/tools/ci_build/github/azure-pipelines/cuda-packaging-pipeline.yml index b24310ac0c3e0..f9363e821a36a 100644 --- a/tools/ci_build/github/azure-pipelines/cuda-packaging-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/cuda-packaging-pipeline.yml @@ -1,125 +1,134 @@ parameters: - - name: RunOnnxRuntimeTests - displayName: Run Tests? - type: boolean - default: true - - - name: UseIncreasedTimeoutForTests - displayName: Increase timeout for tests? Set it to false if you are doing an Onnx Runtime release. - type: boolean - default: false - - - name: DoCompliance - displayName: Run Compliance Tasks? - type: boolean - default: true - - - name: DoEsrp - displayName: Run code sign tasks? Must be true if you are doing an ONNX Runtime release - type: boolean - default: true - - - name: IsReleaseBuild - displayName: Is a release build? Set it to true if you are doing an ONNX Runtime release. - type: boolean - default: false - - - name: PreReleaseVersionSuffixString - displayName: Suffix added to pre-release package version. Only used if IsReleaseBuild is true. Denotes the type of pre-release package. - type: string - values: - - alpha - - beta - - rc - - none - default: none - - - name: PreReleaseVersionSuffixNumber - displayName: Number added to pre-release package version. Only used if IsReleaseBuild is true. Denotes the sequence of a pre-release package. - type: number - default: 0 - - # these 2 parameters are used for debugging. - - name: SpecificArtifact - displayName: Use Specific Artifact (Debugging only) - type: boolean - default: false - - - name: BuildId - displayName: Pipeline BuildId, you could find it in the URL - type: string - default: '0' - - - name: CudaVersion - displayName: CUDA version - type: string - default: '12.2' - values: - - 11.8 - - 12.2 +- name: RunOnnxRuntimeTests + displayName: Run Tests? + type: boolean + default: true + +- name: UseIncreasedTimeoutForTests + displayName: Increase timeout for tests? Set it to false if you are doing an Onnx Runtime release. + type: boolean + default: false + +- name: DoEsrp + displayName: Run code sign tasks? Must be true if you are doing an ONNX Runtime release + type: boolean + default: true + +- name: IsReleaseBuild + displayName: Is a release build? Set it to true if you are doing an ONNX Runtime release. + type: boolean + default: false + +- name: PreReleaseVersionSuffixString + displayName: Suffix added to pre-release package version. Only used if IsReleaseBuild is true. Denotes the type of pre-release package. + type: string + values: + - alpha + - beta + - rc + - none + default: none + +- name: PreReleaseVersionSuffixNumber + displayName: Number added to pre-release package version. Only used if IsReleaseBuild is true. Denotes the sequence of a pre-release package. + type: number + default: 0 + +# these 2 parameters are used for debugging. +- name: SpecificArtifact + displayName: Use Specific Artifact (Debugging only) + type: boolean + default: false + +- name: BuildId + displayName: Pipeline BuildId, you could find it in the URL + type: string + default: '0' + +- name: CudaVersion + displayName: CUDA version + type: string + default: '12.2' + values: + - 12.2 variables: - - template: templates/common-variables.yml - - name: ReleaseVersionSuffix - value: '' - - name: win_trt_home - ${{ if eq(parameters.CudaVersion, '11.8') }}: - value: $(Agent.TempDirectory)\${{ variables.win_trt_folder_cuda11 }} - ${{ if eq(parameters.CudaVersion, '12.2') }}: - value: $(Agent.TempDirectory)\${{ variables.win_trt_folder_cuda12 }} - - name: win_cuda_home - ${{ if eq(parameters.CudaVersion, '11.8') }}: - value: $(Agent.TempDirectory)\v11.8 - ${{ if eq(parameters.CudaVersion, '12.2') }}: - value: $(Agent.TempDirectory)\v12.2 +- template: templates/common-variables.yml +- name: ReleaseVersionSuffix + value: '' +- name: win_trt_home + ${{ if eq(parameters.CudaVersion, '11.8') }}: + value: $(Agent.TempDirectory)\${{ variables.win_trt_folder_cuda11 }} + ${{ if eq(parameters.CudaVersion, '12.2') }}: + value: $(Agent.TempDirectory)\${{ variables.win_trt_folder_cuda12 }} +- name: win_cuda_home + ${{ if eq(parameters.CudaVersion, '11.8') }}: + value: $(Agent.TempDirectory)\v11.8 + ${{ if eq(parameters.CudaVersion, '12.2') }}: + value: $(Agent.TempDirectory)\v12.2 + resources: repositories: - - repository: onnxruntime-inference-examples # The name used to reference this repository in the checkout step - type: github - endpoint: ort-examples - name: microsoft/onnxruntime-inference-examples - - -stages: - # Set ReleaseVersionSuffix - - template: stages/set_packaging_variables_stage.yml - parameters: - IsReleaseBuild: ${{ parameters.IsReleaseBuild }} - PreReleaseVersionSuffixString: ${{ parameters.PreReleaseVersionSuffixString }} - PreReleaseVersionSuffixNumber: ${{ parameters.PreReleaseVersionSuffixNumber }} - - # this is needed for certain artifacts to be published - - stage: Linux_C_API_Packaging_CPU - dependsOn: [ ] - jobs: - - template: templates/c-api-linux-cpu.yml + - repository: onnxruntime-inference-examples # The name used to reference this repository in the checkout step + type: github + endpoint: ort-examples + name: microsoft/onnxruntime-inference-examples + - repository: 1esPipelines + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + +extends: + # The pipeline extends the 1ES PT which will inject different SDL and compliance tasks. + # For non-production pipelines, use "Unofficial" as defined below. + # For productions pipelines, use "Official". + template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines + parameters: + sdl: + binskim: + enabled: true + analyzeTargetGlob: $(Build.ArtifactStagingDirectory)/**.dll + sourceAnalysisPool: + name: onnxruntime-Win-CPU-2022 + os: windows + componentgovernance: + ignoreDirectories: $(Build.SourcesDirectory)/onnxruntime-inference-examples + sourceRepositoriesToScan: + exclude: + - repository: onnxruntime-inference-examples + spotBugs: + enabled: false + justificationForDisabling: "Getting ##[error1. SpotBugs Error gdn.unknownFormatResult - File: spotbugs.xml, which indicates that SpotBugs found one or more errors, which are not handled by the Guardian right now." + stages: + # Set ReleaseVersionSuffix + - template: stages/set_packaging_variables_stage.yml parameters: - OnnxruntimeArch: 'x64' - OnnxruntimeNodejsBindingArch: 'x64' - PoolName: 'onnxruntime-Ubuntu2204-AMD-CPU' - PackageJava: false - PackageNodeJS: false - - # Nuget Packaging - - template: stages/nuget-combine-cuda-stage.yml - parameters: - DoCompliance: ${{ parameters.DoCompliance }} - CudaVersion: ${{ parameters.CudaVersion }} - RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - UseIncreasedTimeoutForTests: ${{ parameters.UseIncreasedTimeoutForTests }} - win_trt_home: ${{ variables.win_trt_home }} - win_cuda_home: ${{ variables.win_cuda_home }} - DoEsrp: ${{ parameters.DoEsrp }} - IsReleaseBuild: ${{ parameters.IsReleaseBuild }} - buildJava: true - buildNodejs: false - SpecificArtifact: ${{ parameters.SpecificArtifact }} - BuildId: ${{ parameters.BuildId }} + IsReleaseBuild: ${{ parameters.IsReleaseBuild }} + PreReleaseVersionSuffixString: ${{ parameters.PreReleaseVersionSuffixString }} + PreReleaseVersionSuffixNumber: ${{ parameters.PreReleaseVersionSuffixNumber }} - - template: stages/download-java-tools-stage.yml + # this is needed for certain artifacts to be published + - template: stages/c-api-linux-cpu-stage.yml - - template: stages/java-cuda-packaging-stage.yml - parameters: - CudaVersion: ${{ parameters.CudaVersion }} - SpecificArtifact: ${{ parameters.SpecificArtifact }} - BuildId: ${{ parameters.BuildId }} + # Nuget Packaging + - template: stages/nuget-combine-cuda-stage.yml + parameters: + CudaVersion: ${{ parameters.CudaVersion }} + RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} + UseIncreasedTimeoutForTests: ${{ parameters.UseIncreasedTimeoutForTests }} + win_trt_home: ${{ variables.win_trt_home }} + win_cuda_home: ${{ variables.win_cuda_home }} + DoEsrp: ${{ parameters.DoEsrp }} + IsReleaseBuild: ${{ parameters.IsReleaseBuild }} + buildJava: true + buildNodejs: false + SpecificArtifact: ${{ parameters.SpecificArtifact }} + BuildId: ${{ parameters.BuildId }} + + - template: stages/download-java-tools-stage.yml + + - template: stages/java-cuda-packaging-stage.yml + parameters: + CudaVersion: ${{ parameters.CudaVersion }} + SpecificArtifact: ${{ parameters.SpecificArtifact }} + BuildId: ${{ parameters.BuildId }} diff --git a/tools/ci_build/github/azure-pipelines/custom-nuget-packaging-pipeline.yml b/tools/ci_build/github/azure-pipelines/custom-nuget-packaging-pipeline.yml new file mode 100644 index 0000000000000..a6ad823594917 --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/custom-nuget-packaging-pipeline.yml @@ -0,0 +1,158 @@ +parameters: +- name: CudaVersion + type: string + default: '12.2' + +- name: QnnSdk + displayName: QNN SDK Version + type: string + default: 2.32.0.250228 + +- name: IsReleaseBuild + displayName: Is a release build? Set it to true if you are doing an Onnx Runtime release. + type: boolean + default: false + +- name: PackageName + displayName: What is the package name? + type: string + default: 'Microsoft.ML.OnnxRuntime.Flamingo' + +variables: + - template: templates/common-variables.yml + - name: ReleaseVersionSuffix + value: '' + - name: win_cuda_home + ${{ if eq(parameters.CudaVersion, '11.8') }}: + value: $(Agent.TempDirectory)\v11.8 + ${{ if eq(parameters.CudaVersion, '12.2') }}: + value: $(Agent.TempDirectory)\v12.2 + +resources: + repositories: + - repository: 1esPipelines + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release +extends: + # The pipeline extends the 1ES PT which will inject different SDL and compliance tasks. + # For non-production pipelines, use "Unofficial" as defined below. + # For productions pipelines, use "Official". + template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines + parameters: + sdl: + sourceAnalysisPool: + name: onnxruntime-Win-CPU-2022 + os: windows + + stages: + - template: templates/win-ci.yml + parameters: + ort_build_pool_name: 'onnxruntime-Win2022-GPU-A10' + DoCompliance: false + DoEsrp: true + stage_name_suffix: CUDA + buildArch: x64 + msbuildPlatform: x64 + packageName: x64-cuda + CudaVersion: ${{ parameters.CudaVersion }} + buildparameter: --use_cuda --cuda_home=${{ variables.win_cuda_home }} --enable_onnx_tests --enable_wcos --use_webgpu --cmake_extra_defines "CMAKE_CUDA_ARCHITECTURES=52-real;61-real;75-real;86-real;89-real;90-virtual" + runTests: false + buildJava: false + java_artifact_id: onnxruntime_gpu + UseIncreasedTimeoutForTests: false + SpecificArtifact: false + BuildId: '0' + + - template: templates/qnn-ep-win.yml + parameters: + qnn_ep_build_pool_name: 'Onnxruntime-QNNEP-Windows-2022-CPU' + QnnSdk: ${{ parameters.QnnSdk }} + IsReleaseBuild: ${{ parameters.IsReleaseBuild }} + DoEsrp: true + ArtifactName: 'drop-nuget-qnn-arm64' + # Add --use_webgpu to enable WebGPU + buildParameter: '--arm64' + buildPlatform: 'ARM64' + buildArch: 'ARM64' + StageName: 'OnnxRuntime_QNN_Nuget_Win_Arm64' + build_config: 'RelWithDebInfo' + PublishArchive: true + + - stage: NugetPackaging + dependsOn: [Windows_Packaging_CUDA, OnnxRuntime_QNN_Nuget_Win_Arm64] + jobs: + - job: CreateNugetPackage + pool: 'Onnxruntime-Win2022-GPU-A10' + timeoutInMinutes: 120 + steps: + - checkout: self + clean: true + submodules: none + + - task: UsePythonVersion@0 + inputs: + versionSpec: '3.12' + addToPath: true + + - task: DownloadPipelineArtifact@0 + displayName: 'Download Pipeline Artifact - managed nuget' + inputs: + artifactName: 'drop-nuget-qnn-arm64' + targetPath: '$(Build.BinariesDirectory)/managed-nuget' + + - task: DownloadPipelineArtifact@0 + displayName: 'Download Pipeline Artifact - win-x64' + inputs: + artifactName: 'onnxruntime-win-x64-cuda' + targetPath: '$(Build.BinariesDirectory)/win-x64' + + - task: DownloadPipelineArtifact@0 + displayName: 'Download Pipeline Artifact - win-arm64' + inputs: + artifactName: 'onnxruntime-win-ARM64-qnn' + targetPath: '$(Build.BinariesDirectory)/win-arm64' + + - task: PowerShell@2 + displayName: 'Extract Nuget Package Version' + inputs: + targetType: 'inline' + script: | + $nupkgs = (Get-ChildItem $(Build.BinariesDirectory)/managed-nuget -Filter Microsoft.ML.OnnxRuntime.Managed.*.nupkg -Recurse) + $package_name = $nupkgs[0].Name + $version_length = $package_name.Length - "Microsoft.ML.OnnxRuntime.Managed.".Length - ".nupkg".Length + $package_version = $package_name.Substring("Microsoft.ML.OnnxRuntime.Managed.".Length, $version_length) + Write-Host "##vso[task.setvariable variable=package_version;]$package_version" + workingDirectory: $(Build.BinariesDirectory) + + - task: PowerShell@2 + displayName: 'Extract Archives' + inputs: + targetType: 'inline' + script: | + Expand-Archive -Path $(Build.BinariesDirectory)/win-x64/onnxruntime-win-x64-cuda*.zip -DestinationPath $(Build.BinariesDirectory)/win-x64 + Expand-Archive -Path $(Build.BinariesDirectory)/win-arm64/onnxruntime-win-ARM64-qnn*.zip -DestinationPath $(Build.BinariesDirectory)/win-arm64 + $win_x64 = (Get-ChildItem -Path $(Build.BinariesDirectory)/win-x64 -Filter onnxruntime-win-x64-cuda*)[0].FullName + $win_arm64 = (Get-ChildItem -Path $(Build.BinariesDirectory)/win-arm64 -Filter onnxruntime-win-ARM64-qnn*)[0].FullName + Write-Host "##vso[task.setvariable variable=win_x64;]$win_x64" + Write-Host "##vso[task.setvariable variable=win_arm64;]$win_arm64" + workingDirectory: $(Build.BinariesDirectory) + + - task: PythonScript@0 + displayName: 'Generate Nuget Package' + inputs: + scriptPath: '$(Build.SourcesDirectory)/tools/nuget/generate_nuspec_for_custom_nuget.py' + arguments: '--nuspec_path "$(Build.BinariesDirectory)/${{ parameters.PackageName }}.nuspec" --root_dir "$(Build.SourcesDirectory)" --commit_id "$(Build.SourceVersion)" --win_arm64 "$(win_arm64)" --win_x64 "$(win_x64)" --package_version "$(package_version)" --package_name "${{ parameters.PackageName }}"' + + - task: NuGetCommand@2 + displayName: 'Pack Nuget Package' + inputs: + command: 'pack' + packagesToPack: '$(Build.BinariesDirectory)/${{ parameters.PackageName }}.nuspec' + packDestination: $(Build.ArtifactStagingDirectory)\ + + - task: 1ES.PublishPipelineArtifact@1 + displayName: 'Publish Artifact: Nuget' + inputs: + artifactName: '${{ parameters.PackageName }}' + targetPath: '$(Build.ArtifactStagingDirectory)' diff --git a/tools/ci_build/github/azure-pipelines/linux-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/linux-ci-pipeline.yml deleted file mode 100644 index c957bb3ade91a..0000000000000 --- a/tools/ci_build/github/azure-pipelines/linux-ci-pipeline.yml +++ /dev/null @@ -1,310 +0,0 @@ -##### start trigger Don't edit it manually, Please do edit set-trigger-rules.py #### -### please do rerun set-trigger-rules.py ### -trigger: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -pr: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -#### end trigger #### - -stages: -- stage: x64 - dependsOn: [] - jobs: - - job: Linux_Debug - timeoutInMinutes: 180 - workspace: - clean: all - variables: - skipComponentGovernanceDetection: true - ORT_CACHE_DIR: $(Agent.TempDirectory)/ort_ccache - TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] - pool: onnxruntime-Ubuntu2204-AMD-CPU - steps: - - - checkout: self - clean: true - submodules: none - - - template: templates/get-docker-image-steps.yml - parameters: - Dockerfile: tools/ci_build/github/linux/docker/inference/x86_64/default/cpu/Dockerfile - Context: tools/ci_build/github/linux/docker/inference/x86_64/default/cpu - DockerBuildArgs: "--build-arg BUILD_UID=$( id -u )" - Repository: onnxruntimecpubuildcentos8x64 - - - template: templates/linux-build-step-with-cache.yml - parameters: - WithCache: false - Today: $(TODAY) - AdditionalKey: onnxruntime_linux_debug_with_address_sanitizer - CacheDir: $(ORT_CACHE_DIR) - ChangeEveryCommit: true - BuildStep: - - task: CmdLine@2 - displayName: 'build' - inputs: - script: | - mkdir -p $HOME/.onnx - docker run -e SYSTEM_COLLECTIONURI --rm \ - --volume /data/onnx:/data/onnx:ro \ - --volume /data/models:/data/models:ro \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - --volume $HOME/.onnx:/home/onnxruntimedev/.onnx \ - -e ALLOW_RELEASED_ONNX_OPSET_ONLY=0 \ - -e NIGHTLY_BUILD \ - -e BUILD_BUILDNUMBER \ - onnxruntimecpubuildcentos8x64 \ - /bin/bash -c 'set -ex; \ - python3 /onnxruntime_src/tools/ci_build/build.py \ - --build_dir /build --cmake_generator Ninja \ - --config Debug \ - --skip_submodule_sync \ - --build_shared_lib \ - --parallel --use_vcpkg --use_vcpkg_ms_internal_asset_cache \ - --enable_onnx_tests --enable_address_sanitizer \ - --update --build; - python3 /onnxruntime_src/tools/ci_build/build.py \ - --build_dir /build --cmake_generator Ninja \ - --config Debug \ - --skip_submodule_sync \ - --build_shared_lib \ - --parallel --use_vcpkg --use_vcpkg_ms_internal_asset_cache \ - --enable_onnx_tests --enable_address_sanitizer \ - --test; - ' - workingDirectory: $(Build.SourcesDirectory) - - - task: PublishTestResults@2 - displayName: 'Publish unit test results' - inputs: - testResultsFiles: '**/*.results.xml' - searchFolder: '$(Build.BinariesDirectory)' - testRunTitle: 'Unit Test Run' - condition: succeededOrFailed() - - - job: Linux_Release - timeoutInMinutes: 180 - workspace: - clean: all - variables: - skipComponentGovernanceDetection: true - ORT_CACHE_DIR: $(Agent.TempDirectory)/ort_ccache - TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] - pool: onnxruntime-Ubuntu2204-AMD-CPU - steps: - - - checkout: self - clean: true - submodules: none - - - task: DownloadPackage@1 - displayName: 'Download ARM64 GCC' - inputs: - packageType: upack - feed: '/7424c8e4-5c62-490e-95c4-79446f31017c' - definition: 'gcc_aarch64_linux_gnu_host_x86_64' - version: 13.2.1 - downloadPath: $(Build.BinariesDirectory)/gcc - - - task: DownloadPackage@1 - displayName: 'Download ARM32 GCC' - inputs: - packageType: upack - feed: '/7424c8e4-5c62-490e-95c4-79446f31017c' - definition: 'gcc_aarch32_linux_gnu_host_x86_64' - version: 13.2.1 - downloadPath: $(Build.BinariesDirectory)/gcc - - - template: templates/get-docker-image-steps.yml - parameters: - Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cpu - Context: tools/ci_build/github/linux/docker/ - DockerBuildArgs: "--build-arg BUILD_UID=$( id -u )" - Repository: onnxruntimecpubuild - - - script: | - set -e -x - # ARM64 build - mkdir -p $(Build.BinariesDirectory)/gccbin - tar -Jxf $(Build.BinariesDirectory)/gcc/arm-gnu-toolchain-13.2.rel1-x86_64-aarch64-none-linux-gnu.tar.xz --strip=1 -C $(Build.BinariesDirectory)/gccbin - export PATH=$(Build.BinariesDirectory)/gccbin/bin:$PATH - mkdir $(Build.BinariesDirectory)/aarch64build - cd $(Build.BinariesDirectory)/aarch64build - cmake $(Build.SourcesDirectory)/cmake -Donnxruntime_ENABLE_CPUINFO=OFF -DPython_EXECUTABLE=/usr/bin/python3 -DPYTHON_EXECUTABLE=/usr/bin/python3 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=$(Build.SourcesDirectory)/cmake/linux_arm64_crosscompile_toolchain.cmake -G Ninja - ninja - rm -rf $(Build.BinariesDirectory)/aarch64build $(Build.BinariesDirectory)/gccbin - # ARM32 build - mkdir -p $(Build.BinariesDirectory)/gccbin - tar -Jxf $(Build.BinariesDirectory)/gcc/arm-gnu-toolchain-13.2.rel1-x86_64-arm-none-linux-gnueabihf.tar.xz --strip=1 -C $(Build.BinariesDirectory)/gccbin - ls $(Build.BinariesDirectory)/gccbin/bin - mkdir $(Build.BinariesDirectory)/arm32build - cd $(Build.BinariesDirectory)/arm32build - cmake $(Build.SourcesDirectory)/cmake -Donnxruntime_ENABLE_CPUINFO=OFF -DPython_EXECUTABLE=/usr/bin/python3 -DPYTHON_EXECUTABLE=/usr/bin/python3 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=$(Build.SourcesDirectory)/cmake/linux_arm32_crosscompile_toolchain.cmake -G Ninja - ninja - rm -rf $(Build.BinariesDirectory)/arm32build $(Build.BinariesDirectory)/gccbin - displayName: Cross-compile for Linux ARM32 and ARM64 - - - template: templates/linux-build-step-with-cache.yml - parameters: - WithCache: true - Today: $(TODAY) - AdditionalKey: onnxruntime - CacheDir: $(ORT_CACHE_DIR) - ChangeEveryCommit: true - BuildStep: - - task: CmdLine@2 - displayName: 'build' - inputs: - script: | - mkdir -p $HOME/.onnx - docker run -e SYSTEM_COLLECTIONURI --rm \ - --volume /data/onnx:/data/onnx:ro \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - --volume $HOME/.onnx:/home/onnxruntimedev/.onnx \ - --volume $(ORT_CACHE_DIR):/cache \ - -e ALLOW_RELEASED_ONNX_OPSET_ONLY=0 \ - -e NIGHTLY_BUILD \ - -e BUILD_BUILDNUMBER \ - -e CCACHE_DIR=/cache \ - onnxruntimecpubuild \ - /bin/bash -c ' - set -ex; \ - ccache -s; \ - PATH=/opt/python/cp310-cp310/bin:$PATH python /onnxruntime_src/tools/ci_build/build.py \ - --build_dir /build --cmake_generator Ninja \ - --config Release \ - --skip_submodule_sync \ - --build_shared_lib \ - --parallel --use_vcpkg --use_vcpkg_ms_internal_asset_cache --use_binskim_compliant_compile_flags \ - --build_wheel \ - --build_csharp \ - --enable_onnx_tests \ - --enable_transformers_tool_test \ - --use_cache \ - --update --build --cmake_extra_defines onnxruntime_BUILD_BENCHMARKS=ON; \ - ccache -sv; \ - ccache -z' - workingDirectory: $(Build.SourcesDirectory) - - - script: | - ln -s /data/models $(Build.BinariesDirectory)/models - displayName: link model dir - - - bash: | - mkdir -p $HOME/.onnx - docker run -e SYSTEM_COLLECTIONURI --rm \ - --volume /data/onnx:/data/onnx:ro \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - --volume /data/models:/build/models:ro \ - --volume $HOME/.onnx:/home/onnxruntimedev/.onnx \ - -e ALLOW_RELEASED_ONNX_OPSET_ONLY=0 \ - -e NIGHTLY_BUILD \ - -e BUILD_BUILDNUMBER \ - onnxruntimecpubuild \ - /bin/bash -c " - set -ex; \ - pushd /onnxruntime_src/csharp; \ - dotnet restore /onnxruntime_src/csharp/OnnxRuntime.DesktopOnly.CSharp.sln; \ - dotnet build /onnxruntime_src/csharp/OnnxRuntime.DesktopOnly.CSharp.sln -c Release; \ - dotnet test /onnxruntime_src/csharp/OnnxRuntime.DesktopOnly.CSharp.sln -c Release -f net8.0 --no-build -l \"console;verbosity=normal\"; \ - popd - " - displayName: 'Dotnet build C# sln and Test' - - - bash: | - mkdir -p $HOME/.onnx - docker run -e SYSTEM_COLLECTIONURI --rm \ - --volume /data/onnx:/data/onnx:ro \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - --volume /data/models:/build/models:ro \ - --volume $HOME/.onnx:/home/onnxruntimedev/.onnx \ - -e ALLOW_RELEASED_ONNX_OPSET_ONLY=0 \ - -e NIGHTLY_BUILD \ - -e BUILD_BUILDNUMBER \ - onnxruntimecpubuild \ - /bin/bash -c " - set -ex; \ - /bin/bash /onnxruntime_src/tools/scripts/python_test.sh /onnxruntime_src /build Release && \ - /bin/bash /onnxruntime_src/tools/scripts/symbolic_shape_infer_test.sh /build - " - displayName: 'Run Release tests and symbolic shape infer test' - - - template: templates/check_test_result.yml - parameters: - FileName: '$(Build.BinariesDirectory)/Release/onnxruntime_test_all.Release.results.xml' - - - task: PublishTestResults@2 - displayName: 'Publish unit test results' - inputs: - testResultsFiles: '**/*.results.xml' - searchFolder: '$(Build.BinariesDirectory)' - testRunTitle: 'Unit Test Run' - condition: succeededOrFailed() - -- stage: arm64_build - dependsOn: [] - jobs: - - template: templates/py-linux.yml - parameters: - arch: 'aarch64' - machine_pool: 'onnxruntime-linux-ARM64-CPU-2019' - with_cache: true - cmake_build_type: Release - python_exe_path: '/opt/python/cp310-cp310/bin/python3.10' - -- stage: arm64_test - dependsOn: ['arm64_build'] - jobs: - - template: templates/py-packaging-linux-test-cpu.yml - parameters: - arch: 'aarch64' - ep: 'cpu' - machine_pool: 'onnxruntime-linux-ARM64-CPU-2019' - -- stage: arm64_build_xnnpack - dependsOn: [] - jobs: - - template: templates/py-linux.yml - parameters: - arch: 'aarch64' - machine_pool: 'onnxruntime-linux-ARM64-CPU-2019' - with_cache: true - cmake_build_type: Release - ep: 'XNNPack' - extra_build_arg: '--use_xnnpack' - python_exe_path: '/opt/python/cp310-cp310/bin/python3.10' - -- stage: arm64_test_xnnpack - dependsOn: ['arm64_build_xnnpack'] - jobs: - - template: templates/py-packaging-linux-test-cpu.yml - parameters: - arch: 'aarch64' - ep: 'XNNPack' - machine_pool: 'onnxruntime-linux-ARM64-CPU-2019' diff --git a/tools/ci_build/github/azure-pipelines/linux-dnnl-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/linux-dnnl-ci-pipeline.yml deleted file mode 100644 index eafab4829a8db..0000000000000 --- a/tools/ci_build/github/azure-pipelines/linux-dnnl-ci-pipeline.yml +++ /dev/null @@ -1,84 +0,0 @@ -##### start trigger Don't edit it manually, Please do edit set-trigger-rules.py #### -### please do rerun set-trigger-rules.py ### -trigger: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -pr: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -#### end trigger #### - -jobs: -- job: Linux_py_Wheels - timeoutInMinutes: 180 - variables: - skipComponentGovernanceDetection: true - workspace: - clean: all - pool: Linux-CPU-2019 - steps: - - checkout: self - clean: true - submodules: none - - - template: templates/get-docker-image-steps.yml - parameters: - Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cpu - Context: tools/ci_build/github/linux/docker - DockerBuildArgs: "--build-arg BUILD_UID=$( id -u )" - Repository: onnxruntimecpubuild - - - task: CmdLine@2 - displayName: 'Build and test' - inputs: - script: | - mkdir -p $HOME/.onnx - docker run -e SYSTEM_COLLECTIONURI --rm \ - --volume /data/onnx:/data/onnx:ro \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - --volume /data/models:/build/models:ro \ - --volume $HOME/.onnx:/home/onnxruntimedev/.onnx \ - -e NIGHTLY_BUILD \ - -e BUILD_BUILDNUMBER \ - onnxruntimecpubuild \ - bash -c 'PATH=/opt/python/cp310-cp310/bin:$PATH python /onnxruntime_src/tools/ci_build/build.py \ - --build_dir /build \ - --config Debug Release \ - --skip_submodule_sync \ - --build_shared_lib \ - --parallel --use_vcpkg --use_vcpkg_ms_internal_asset_cache \ - --enable_pybind \ - --enable_onnx_tests \ - --build_java \ - --use_dnnl' - workingDirectory: $(Build.SourcesDirectory) - - - task: PublishTestResults@2 - displayName: 'Publish unit test results' - inputs: - testResultsFiles: '**/*.results.xml' - searchFolder: '$(Build.BinariesDirectory)' - testRunTitle: 'Unit Test Run' - condition: succeededOrFailed() - diff --git a/tools/ci_build/github/azure-pipelines/linux-gpu-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/linux-gpu-ci-pipeline.yml deleted file mode 100644 index 665b7435eed66..0000000000000 --- a/tools/ci_build/github/azure-pipelines/linux-gpu-ci-pipeline.yml +++ /dev/null @@ -1,222 +0,0 @@ -##### start trigger Don't edit it manually, Please do edit set-trigger-rules.py #### -### please do rerun set-trigger-rules.py ### -trigger: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -pr: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -#### end trigger #### -parameters: - - name: CudaVersion - displayName: CUDA version - type: string - default: '12.2' - values: - - 11.8 - - 12.2 - - - name: SpecificArtifact - displayName: Use Specific Artifact - type: boolean - default: false - - - name: BuildId - displayName: Specific Artifact's BuildId - type: string - default: '0' - -variables: - - name: docker_base_image - ${{ if eq(parameters.CudaVersion, '11.8') }}: - value: onnxruntimebuildcache.azurecr.io/internal/azureml/onnxruntime/build/cuda11_x64_almalinux8_gcc11:20250124.1 - ${{ if eq(parameters.CudaVersion, '12.2') }}: - value: onnxruntimebuildcache.azurecr.io/internal/azureml/onnxruntime/build/cuda12_x64_ubi8_gcc12:20250124.1 - - - name: Repository - ${{ if eq(parameters.CudaVersion, '11.8') }}: - value: 'onnxruntimecuda11manylinuxbuild' - ${{ if eq(parameters.CudaVersion, '12.2') }}: - value: 'onnxruntimecuda12manylinuxbuild' - -stages: -- stage: Linux_Build - jobs: - - job: Linux_Build - timeoutInMinutes: 120 - variables: - skipComponentGovernanceDetection: true - CCACHE_DIR: $(Pipeline.Workspace)/ccache - workspace: - clean: all - pool: onnxruntime-Ubuntu2204-AMD-CPU - - steps: - - - checkout: self - clean: true - submodules: none - - - template: templates/get-docker-image-steps.yml - parameters: - Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda - Context: tools/ci_build/github/linux/docker - DockerBuildArgs: "--build-arg BASEIMAGE=$(docker_base_image) --build-arg BUILD_UID=$( id -u )" - Repository: $(Repository) - - - task: Cache@2 - inputs: - key: '"ccache" | "${{parameters.CudaVersion}}" |"$(Build.SourceBranch)" | "$(Build.SourceVersion)"' - path: $(CCACHE_DIR) - restoreKeys: | - "ccache" | "${{parameters.CudaVersion}}" | "$(Build.SourceBranch)" - "ccache" - cacheHitVar: CACHE_RESTORED - displayName: Cach Task - - - script: | - sudo mkdir -p $(Pipeline.Workspace)/ccache - condition: ne(variables.CACHE_RESTORED, 'true') - displayName: Create Cache Dir - - - script: | - set -e -x - mkdir -p $HOME/.onnx - docker run --rm \ - --volume /data/onnx:/data/onnx:ro \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - --volume /data/models:/build/models:ro \ - --volume $HOME/.onnx:/home/onnxruntimedev/.onnx \ - --volume $(Pipeline.Workspace)/ccache:/cache \ - -e ALLOW_RELEASED_ONNX_OPSET_ONLY=0 \ - -e NIGHTLY_BUILD \ - -e BUILD_BUILDNUMBER \ - -e CCACHE_DIR=/cache -w /onnxruntime_src \ - $(Repository) tools/ci_build/github/linux/build_cuda_ci.sh - workingDirectory: $(Build.SourcesDirectory) - displayName: Build Onnxruntime - - - script: $(Build.SourcesDirectory)/tools/ci_build/github/linux/delete_unused_files_before_upload.sh - - - task: PublishPipelineArtifact@0 - displayName: 'Publish Pipeline Artifact' - inputs: - artifactName: 'drop-linux' - targetPath: '$(Build.BinariesDirectory)/Release' - - - template: templates/explicitly-defined-final-tasks.yml - -- stage: Linux_Test - dependsOn: - - Linux_Build - jobs: - - job: Linux_Test - timeoutInMinutes: 180 - variables: - skipComponentGovernanceDetection: true - workspace: - clean: all - pool: Onnxruntime-Linux-GPU-A100-WUS3 - steps: - - checkout: self - clean: true - submodules: none - - - template: templates/flex-downloadPipelineArtifact.yml - parameters: - ArtifactName: 'drop-linux' - StepName: 'Download Pipeline Artifact - Linux Build' - TargetPath: '$(Build.BinariesDirectory)/Release' - SpecificArtifact: ${{ parameters.SpecificArtifact }} - BuildId: ${{ parameters.BuildId }} - - - template: templates/get-docker-image-steps.yml - parameters: - Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda - Context: tools/ci_build/github/linux/docker - DockerBuildArgs: "--build-arg BASEIMAGE=$(docker_base_image) --build-arg BUILD_UID=$( id -u )" - Repository: $(Repository) - - - task: CmdLine@2 - inputs: - script: | - set -e -x - mkdir -p $HOME/.onnx - docker run --gpus all --rm \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory)/Release:/build/Release \ - --volume /data/models:/build/models:ro \ - --volume $HOME/.onnx:/home/onnxruntimedev/.onnx \ - --volume /data/onnx:/data/onnx \ - -e NVIDIA_TF32_OVERRIDE=0 \ - $(Repository) \ - /bin/bash -c ' - set -e - nvidia-smi; \ - /sbin/ldconfig -N -v $(sed "s/:/ /" <<< $LD_LIBRARY_PATH) 2>/dev/null | grep -E "libcudart.so|libcudnn.so|libnvinfer.so"; \ - cat /usr/local/cuda/include/cuda.h | grep -m1 CUDA_VERSION; \ - cat /usr/include/cudnn_version.h | grep CUDNN_MAJOR -m1 -A 2; \ - export PATH=/opt/python/cp312-cp312/bin:$PATH; \ - python3 -m pip install /build/Release/dist/*.whl; \ - python3 -u -c "from onnxruntime.capi._pybind_state import (OrtDevice as C_OrtDevice) ; \ - ort_device = C_OrtDevice(C_OrtDevice.cuda(), C_OrtDevice.default_memory(), 0); \ - print(ort_device); print(ort_device.device_type(), C_OrtDevice.cuda()); \ - assert(ort_device.device_type()==1); assert(C_OrtDevice.cuda()==1);" \ - ' - displayName: 'Check GPU' - - - task: CmdLine@2 - inputs: - script: | - set -e -x - mkdir -p $HOME/.onnx - docker run --gpus all --shm-size=1g --ipc=host --ulimit memlock=-1 --ulimit stack=67108864 --rm \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory)/Release:/build/Release \ - --volume /data/models:/build/models:ro \ - --volume $HOME/.onnx:/home/onnxruntimedev/.onnx \ - --volume /data/onnx:/data/onnx \ - -e NVIDIA_TF32_OVERRIDE=0 \ - $(Repository) \ - /bin/bash -c ' - set -ex; \ - cp /onnxruntime_src/tools/ci_build/github/linux/docker/scripts/manylinux/requirements.txt /tmp/requirements.txt; \ - export PATH=/opt/python/cp312-cp312/bin:$PATH; \ - python3 -m pip install -r /tmp/requirements.txt; \ - python3 -m pip install /build/Release/dist/*.whl; \ - cd /build/Release && xargs -a /build/Release/perms.txt chmod a+x; \ - cd /onnxruntime_src/java && /onnxruntime_src/java/gradlew cmakeCheck -DcmakeBuildDir=/build/Release -DUSE_CUDA=1; \ - cd /tmp; \ - python3 /onnxruntime_src/tools/ci_build/build.py \ - --build_dir /build --config Release --test --skip_submodule_sync --build_shared_lib --parallel --use_vcpkg --use_vcpkg_ms_internal_asset_cache --use_binskim_compliant_compile_flags --build_wheel --enable_onnx_tests \ - --enable_transformers_tool_test --use_cuda --cuda_version=${{parameters.CudaVersion}} --cuda_home=/usr/local/cuda --cudnn_home=/usr/local/cuda \ - --enable_pybind --build_java --ctest_path "" ; \ - ' - displayName: 'Run Tests' - - - template: templates/check_test_result.yml - parameters: - FileName: '$(Build.BinariesDirectory)/Release/onnxruntime_test_all.Release.results.xml' - - - template: templates/clean-agent-build-directory-step.yml diff --git a/tools/ci_build/github/azure-pipelines/linux-gpu-tensorrt-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/linux-gpu-tensorrt-ci-pipeline.yml deleted file mode 100644 index dd5288ab3a436..0000000000000 --- a/tools/ci_build/github/azure-pipelines/linux-gpu-tensorrt-ci-pipeline.yml +++ /dev/null @@ -1,105 +0,0 @@ -##### start trigger Don't edit it manually, Please do edit set-trigger-rules.py #### -### please do rerun set-trigger-rules.py ### -trigger: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -pr: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -#### end trigger #### -parameters: - - name: CudaVersion - displayName: CUDA version - type: string - default: '12.2' - values: - - 11.8 - - 12.2 - -variables: - - template: templates/common-variables.yml - - name: docker_base_image - ${{ if eq(parameters.CudaVersion, '11.8') }}: - value: onnxruntimebuildcache.azurecr.io/internal/azureml/onnxruntime/build/cuda11_x64_almalinux8_gcc11:20250124.1 - ${{ if eq(parameters.CudaVersion, '12.2') }}: - value: onnxruntimebuildcache.azurecr.io/internal/azureml/onnxruntime/build/cuda12_x64_ubi8_gcc12:20250124.1 - - name: linux_trt_version - ${{ if eq(parameters.CudaVersion, '11.8') }}: - value: ${{ variables.linux_trt_version_cuda11 }} - ${{ if eq(parameters.CudaVersion, '12.2') }}: - value: ${{ variables.linux_trt_version_cuda12 }} - -jobs: -- job: Linux_Build - timeoutInMinutes: 180 - variables: - skipComponentGovernanceDetection: true - ALLOW_RELEASED_ONNX_OPSET_ONLY: '1' - ORT_CACHE_DIR: '$(Agent.TempDirectory)/ort/ccache' - TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] - workspace: - clean: all - pool: onnxruntime-tensorrt-linuxbuild-T4 - steps: - - - checkout: self - clean: true - submodules: none - - - template: templates/get-docker-image-steps.yml - parameters: - Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda - Context: tools/ci_build/github/linux/docker - DockerBuildArgs: " - --network=host - --build-arg BASEIMAGE=${{ variables.docker_base_image }} - --build-arg TRT_VERSION=${{ variables.linux_trt_version }} - --build-arg BUILD_UID=$( id -u ) - " - Repository: onnxruntimetensorrt86gpubuild - - - template: templates/linux-build-step-with-cache.yml - parameters: - WithCache: true - Today: $(TODAY) - AdditionalKey: gpu_tensorrt - CacheDir: '$(ORT_CACHE_DIR)' - BuildStep: - - task: CmdLine@2 - inputs: - script: | - docker run -e SYSTEM_COLLECTIONURI --gpus all --rm \ - --volume /data/onnx:/data/onnx:ro \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - --volume /data/models:/build/models:ro \ - --volume $HOME/.onnx:/home/onnxruntimedev/.onnx \ - --volume $(ORT_CACHE_DIR):/cache \ - -e ALLOW_RELEASED_ONNX_OPSET_ONLY=0 \ - -e NIGHTLY_BUILD \ - -e BUILD_BUILDNUMBER \ - -e CCACHE_DIR=/cache -w /onnxruntime_src \ - onnxruntimetensorrt86gpubuild tools/ci_build/github/linux/build_tensorrt_ci.sh - workingDirectory: $(Build.SourcesDirectory) - - - template: templates/explicitly-defined-final-tasks.yml diff --git a/tools/ci_build/github/azure-pipelines/linux-gpu-tensorrt-cuda-minimal-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/linux-gpu-tensorrt-cuda-minimal-ci-pipeline.yml index ad9d9bfc4b5e5..0ec05909b846f 100644 --- a/tools/ci_build/github/azure-pipelines/linux-gpu-tensorrt-cuda-minimal-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/linux-gpu-tensorrt-cuda-minimal-ci-pipeline.yml @@ -33,7 +33,6 @@ parameters: type: string default: '12.2' values: - - 11.8 - 12.2 variables: diff --git a/tools/ci_build/github/azure-pipelines/linux-gpu-tensorrt-daily-perf-pipeline.yml b/tools/ci_build/github/azure-pipelines/linux-gpu-tensorrt-daily-perf-pipeline.yml index c44d3cff09e96..c00cbb06f26fd 100644 --- a/tools/ci_build/github/azure-pipelines/linux-gpu-tensorrt-daily-perf-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/linux-gpu-tensorrt-daily-perf-pipeline.yml @@ -8,10 +8,9 @@ parameters: - name: TrtVersion displayName: TensorRT Version type: string - default: 10.8_cuda12.6_cudnn9 + default: 10.9_cuda12.8_cudnn9 values: - - 10.8_cuda11.8_cudnn8 - - 10.8_cuda12.6_cudnn9 + - 10.9_cuda12.8_cudnn9 - BIN - name: UseTensorrtOssParser @@ -192,8 +191,4 @@ jobs: pathtoPublish: '$(Build.SourcesDirectory)/Artifact' artifactName: 'result-$(Build.BuildNumber)' - - template: templates/component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' - - template: templates/clean-agent-build-directory-step.yml \ No newline at end of file diff --git a/tools/ci_build/github/azure-pipelines/linux-openvino-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/linux-openvino-ci-pipeline.yml index c7b814f3dd52c..48627e656b9a8 100644 --- a/tools/ci_build/github/azure-pipelines/linux-openvino-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/linux-openvino-ci-pipeline.yml @@ -33,5 +33,5 @@ jobs: parameters: AgentPool : 'Linux-CPU-2019' JobName: 'Linux_CI_Dev' - RunDockerBuildArgs: '-o ubuntu22.04 -p 3.10 -d openvino -v 2024.5.0 -x "--use_openvino CPU --build_wheel"' + RunDockerBuildArgs: '-o ubuntu22.04 -p 3.10 -d openvino -v 2025.0.0 -x "--enable_generic_interface --use_openvino CPU --build_wheel"' TimeoutInMinutes: 120 diff --git a/tools/ci_build/github/azure-pipelines/linux-qnn-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/linux-qnn-ci-pipeline.yml index f78dd44b49ec3..704860587459a 100644 --- a/tools/ci_build/github/azure-pipelines/linux-qnn-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/linux-qnn-ci-pipeline.yml @@ -33,7 +33,7 @@ parameters: - name: QnnSdk displayName: QNN SDK version type: string - default: 2.31.0.250130 + default: 2.32.0.250228 jobs: - job: Build_QNN_EP @@ -90,7 +90,7 @@ jobs: inputs: script: | ./build/Release/onnx_test_runner -e qnn \ - -v -j 1 -i "backend_path|$(QnnSDKRootDir)/lib/x86_64-linux-clang/libQnnCpu.so" \ + -j 1 -i "backend_path|$(QnnSDKRootDir)/lib/x86_64-linux-clang/libQnnCpu.so" \ cmake/external/onnx/onnx/backend/test/data/node - task: CmdLine@2 @@ -98,7 +98,7 @@ jobs: inputs: script: | ./build/Release/onnx_test_runner -e qnn \ - -v -j 1 -i "backend_path|$(QnnSDKRootDir)/lib/x86_64-linux-clang/libQnnCpu.so" \ + -j 1 -i "backend_path|$(QnnSDKRootDir)/lib/x86_64-linux-clang/libQnnCpu.so" \ /data/float32_models - task: CmdLine@2 @@ -106,7 +106,7 @@ jobs: inputs: script: | ./build/Release/onnx_test_runner -e qnn \ - -v -j 1 -i "backend_path|$(QnnSDKRootDir)/lib/x86_64-linux-clang/libQnnHtp.so" \ + -j 1 -i "backend_path|$(QnnSDKRootDir)/lib/x86_64-linux-clang/libQnnHtp.so" \ /data/qdq_models - task: CmdLine@2 @@ -114,5 +114,5 @@ jobs: inputs: script: | ./build/Release/onnx_test_runner -e qnn \ - -v -f -j 1 -i "backend_path|$(QnnSDKRootDir)/lib/x86_64-linux-clang/libQnnHtp.so" \ + -f -j 1 -i "backend_path|$(QnnSDKRootDir)/lib/x86_64-linux-clang/libQnnHtp.so" \ /data/qdq_models/mobilenetv2-1.0_add_transpose_quant diff --git a/tools/ci_build/github/azure-pipelines/mac-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/mac-ci-pipeline.yml deleted file mode 100644 index f3465a8eea8b5..0000000000000 --- a/tools/ci_build/github/azure-pipelines/mac-ci-pipeline.yml +++ /dev/null @@ -1,37 +0,0 @@ -##### start trigger Don't edit it manually, Please do edit set-trigger-rules.py #### -### please do rerun set-trigger-rules.py ### -trigger: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -pr: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -#### end trigger #### - -stages: -- template: templates/mac-cpu-packaging-pipeline.yml - parameters: - AllowReleasedOpsetOnly: 0 - BuildForAllArchs: false - AdditionalBuildFlags: --build_objc --build_wheel --use_xnnpack - WithCache: true diff --git a/tools/ci_build/github/azure-pipelines/mac-coreml-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/mac-coreml-ci-pipeline.yml deleted file mode 100644 index 42f5340730a69..0000000000000 --- a/tools/ci_build/github/azure-pipelines/mac-coreml-ci-pipeline.yml +++ /dev/null @@ -1,68 +0,0 @@ -##### start trigger Don't edit it manually, Please do edit set-trigger-rules.py #### -### please do rerun set-trigger-rules.py ### -trigger: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -pr: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -#### end trigger #### - -jobs: -- job: CoreML_CI - workspace: - clean: all - pool: - vmImage: 'macOS-13' - variables: - MACOSX_DEPLOYMENT_TARGET: '13.3' - TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] - CCACHE_DIR: '$(Pipeline.Workspace)/ccache' - timeoutInMinutes: 120 - steps: - - script: brew install coreutils ninja - displayName: Install coreutils and ninja - - - template: templates/use-xcode-version.yml - - - template: templates/mac-build-step-with-cache.yml - parameters: - WithCache: true - Today: $(TODAY) - AdditionalKey: coreml - CacheDir: $(CCACHE_DIR) - BuildStep: - - script: | - set -e - python3 tools/ci_build/build.py \ - --build_dir build \ - --skip_submodule_sync \ - --cmake_generator=Ninja \ - --parallel --use_vcpkg --use_vcpkg_ms_internal_asset_cache --use_binskim_compliant_compile_flags \ - --build_shared_lib \ - --config Debug \ - --use_cache \ - --use_coreml - displayName: CoreML EP, Build and Test on macOS - env: - CCACHE_COMPILERCHECK: content diff --git a/tools/ci_build/github/azure-pipelines/mac-ios-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/mac-ios-ci-pipeline.yml deleted file mode 100644 index 26b072ed55b04..0000000000000 --- a/tools/ci_build/github/azure-pipelines/mac-ios-ci-pipeline.yml +++ /dev/null @@ -1,81 +0,0 @@ -##### start trigger Don't edit it manually, Please do edit set-trigger-rules.py #### -### please do rerun set-trigger-rules.py ### -trigger: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -pr: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -#### end trigger #### - -jobs: -- job: iOS_CI_on_Mac - pool: - vmImage: 'macOS-13' - variables: - PROTO_CACHE_DIR: $(Pipeline.Workspace)/proto_ccache - ORT_CACHE_DIR: $(Pipeline.Workspace)/ort_ccache - TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] - # Note: Keep the Xcode version and iOS simulator version compatible. - # Check the table here to see what iOS simulator versions are supported by a particular Xcode version: - # https://developer.apple.com/support/xcode/ - XCODE_VERSION: 14.3.1 - IOS_SIMULATOR_RUNTIME_VERSION: 16.4 - timeoutInMinutes: 150 - steps: - - template: templates/use-xcode-version.yml - parameters: - xcodeVersion: $(XCODE_VERSION) - - - template: templates/mac-build-step-with-cache.yml - parameters: - WithCache: true - Today: $(TODAY) - AdditionalKey: onnxruntime - CacheDir: $(ORT_CACHE_DIR) - ChangeEveryCommit: true - BuildStep: - - script: | - python3 $(Build.SourcesDirectory)/tools/ci_build/build.py \ - --skip_submodule_sync \ - --build_dir $(Build.BinariesDirectory)/iOS \ - --build_shared_lib \ - --use_coreml \ - --use_xnnpack \ - --ios \ - --apple_sysroot iphonesimulator \ - --osx_arch x86_64 \ - --apple_deploy_target=15.1 \ - --use_xcode \ - --config RelWithDebInfo \ - --build_apple_framework \ - --parallel --use_binskim_compliant_compile_flags - displayName: (CPU, CoreML, XNNPACK EPs) Build onnxruntime for iOS x86_64 and run tests using simulator - env: - CC: clang - CXX: clang++ - CCACHE_CPP2: 1 - CCACHE_DEPEND: 1 - CCACHE_SLOPPINESS: modules - CCACHE_DIR: $(ORT_CACHE_DIR) - ORT_GET_SIMULATOR_DEVICE_INFO_REQUESTED_RUNTIME_VERSION: $(IOS_SIMULATOR_RUNTIME_VERSION) diff --git a/tools/ci_build/github/azure-pipelines/mac-ios-packaging-pipeline.yml b/tools/ci_build/github/azure-pipelines/mac-ios-packaging-pipeline.yml index 23c968f35a27f..70d8e954808a5 100644 --- a/tools/ci_build/github/azure-pipelines/mac-ios-packaging-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/mac-ios-packaging-pipeline.yml @@ -56,7 +56,7 @@ extends: # Update the pool with your team's 1ES hosted pool. pool: name: "Azure Pipelines" - image: "macOS-13" + image: "macOS-14" os: macOS sdl: sourceAnalysisPool: diff --git a/tools/ci_build/github/azure-pipelines/nodejs/templates/test.yml b/tools/ci_build/github/azure-pipelines/nodejs/templates/test.yml index 9b2d7284cf342..28ece85428287 100644 --- a/tools/ci_build/github/azure-pipelines/nodejs/templates/test.yml +++ b/tools/ci_build/github/azure-pipelines/nodejs/templates/test.yml @@ -33,8 +33,4 @@ steps: node -p "require('onnxruntime-node')" workingDirectory: '$(Build.BinariesDirectory)/e2e_test' -- template: ../../templates/component-governance-component-detection-steps.yml - parameters : - condition : 'always' - - template: ../../templates/clean-agent-build-directory-step.yml diff --git a/tools/ci_build/github/azure-pipelines/nodejs/templates/test_linux.yml b/tools/ci_build/github/azure-pipelines/nodejs/templates/test_linux.yml index 1d3e92056ebe2..c9d56c3474c3e 100644 --- a/tools/ci_build/github/azure-pipelines/nodejs/templates/test_linux.yml +++ b/tools/ci_build/github/azure-pipelines/nodejs/templates/test_linux.yml @@ -10,11 +10,16 @@ stages: - job: Nodejs_Test_${{ parameters.StageSuffix }} workspace: clean: all - timeoutInMinutes: 120 - pool: ${{ parameters.AgentPool }} + timeoutInMinutes: 120 + pool: + name: ${{ parameters.AgentPool }} + os: 'linux' variables: - name: OnnxRuntimeBuildDirectory value: '$(Build.BinariesDirectory)' steps: + - task: NodeTool@0 + inputs: + versionSpec: '20.x' - template: test.yml diff --git a/tools/ci_build/github/azure-pipelines/nodejs/templates/test_macos.yml b/tools/ci_build/github/azure-pipelines/nodejs/templates/test_macos.yml index 4518a168879a2..68b8f3ae90fa6 100644 --- a/tools/ci_build/github/azure-pipelines/nodejs/templates/test_macos.yml +++ b/tools/ci_build/github/azure-pipelines/nodejs/templates/test_macos.yml @@ -11,7 +11,9 @@ stages: clean: all timeoutInMinutes: 120 pool: - vmImage: 'macOS-13' + name: 'Azure Pipelines' + image: 'macOS-14' + os: 'macOS' variables: - name: OnnxRuntimeBuildDirectory diff --git a/tools/ci_build/github/azure-pipelines/nodejs/templates/test_win.yml b/tools/ci_build/github/azure-pipelines/nodejs/templates/test_win.yml index 667c4f2e70a63..5214a772f1a8f 100644 --- a/tools/ci_build/github/azure-pipelines/nodejs/templates/test_win.yml +++ b/tools/ci_build/github/azure-pipelines/nodejs/templates/test_win.yml @@ -10,8 +10,9 @@ stages: - job: Nodejs_Test_${{ parameters.StageSuffix }} workspace: clean: all - timeoutInMinutes: 120 - pool: ${{ parameters.AgentPool }} + timeoutInMinutes: 120 + pool: + name: ${{ parameters.AgentPool }} variables: - name: OnnxRuntimeBuildDirectory value: '$(Build.BinariesDirectory)' diff --git a/tools/ci_build/github/azure-pipelines/npm-packaging-pipeline.yml b/tools/ci_build/github/azure-pipelines/npm-packaging-pipeline.yml index 73719426e2875..e5d45f9f07bfb 100644 --- a/tools/ci_build/github/azure-pipelines/npm-packaging-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/npm-packaging-pipeline.yml @@ -35,71 +35,87 @@ resources: endpoint: Microsoft name: pypa/manylinux ref: 5eda9aded5462201e6310105728d33016e637ea7 - -stages: -- template: templates/web-ci.yml + - repository: 1esPipelines + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release +extends: + # The pipeline extends the 1ES PT which will inject different SDL and compliance tasks. + # For non-production pipelines, use "Unofficial" as defined below. + # For productions pipelines, use "Official". + template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines parameters: - NpmPackagingMode: ${{ variables.NpmPackagingMode }} - IsReleasePipeline: true - PoolName: 'onnxruntime-Ubuntu2204-AMD-CPU' - PackageName: 'onnxruntime-web' - ExtraBuildArgs: '' - UseWebPoolName: true - RunWebGpuTestsForDebugBuild: false - RunWebGpuTestsForReleaseBuild: true - WebGpuPoolName: 'onnxruntime-Win2022-VS2022-webgpu-A10' - WebCpuPoolName: 'onnxruntime-Win2022-VS2022-webgpu-A10' + # Update the pool with your team's 1ES hosted pool. + sdl: + sourceAnalysisPool: + name: onnxruntime-Win-CPU-2022 + os: windows + stages: + - template: templates/web-ci.yml + parameters: + NpmPackagingMode: ${{ variables.NpmPackagingMode }} + IsReleasePipeline: true + PoolName: 'onnxruntime-Ubuntu2204-AMD-CPU' + PackageName: 'onnxruntime-web' + ExtraBuildArgs: '' + UseWebPoolName: true + RunWebGpuTestsForDebugBuild: false + RunWebGpuTestsForReleaseBuild: true + WebGpuPoolName: 'onnxruntime-Win2022-VS2022-webgpu-A10' + WebCpuPoolName: 'onnxruntime-Win2022-VS2022-webgpu-A10' + is1ES: true -- template: templates/react-native-ci.yml - parameters: - NpmPackagingMode: ${{ variables.NpmPackagingMode }} - BuildConfig: 'Release' - PoolName: 'onnxruntime-Ubuntu2204-AMD-CPU' - PackageName: 'onnxruntime-react-native' - InitialStageDependsOn: 'Precheck_and_extract_commit' - enable_code_sign: false + - template: templates/react-native-ci.yml + parameters: + NpmPackagingMode: ${{ variables.NpmPackagingMode }} + BuildConfig: 'Release' + PoolName: 'onnxruntime-Ubuntu2204-AMD-CPU' + PackageName: 'onnxruntime-react-native' + InitialStageDependsOn: 'Precheck_and_extract_commit' + enable_code_sign: false + is1ES: true -- stage: Download_Node_Package_And_Publish_Validation_Script - dependsOn: - - ReactNative_CI_Android - - ReactNative_CI_iOS - - Build_web_Release - - Build_web_Debug - jobs: - - job: Download_Node_Package_And_Publish_Validation_Script - pool: 'Onnxruntime-Win-CPU-2022' - variables: - runCodesignValidationInjection: false - timeoutInMinutes: 10 - steps: -# This pipeline usually are triggered by Zip-Nuget-Java-Nodejs Packaging Pipeline, -# The NPM_packages is from Android_Java_API_AAR_Packaging_QNN, not from RN_CI - - download: build - artifact: 'NPM_packages' - displayName: 'Download NPM_packages from Zip-Nuget-Java-Nodejs Packaging Pipeline Pipeline Artifact' + - stage: Download_Node_Package_And_Publish_Validation_Script + dependsOn: + - ReactNative_CI_Android + - ReactNative_CI_iOS + - Build_web_Release + - Build_web_Debug + jobs: + - job: Download_Node_Package_And_Publish_Validation_Script + pool: 'Onnxruntime-Win-CPU-2022' + variables: + runCodesignValidationInjection: false + timeoutInMinutes: 10 + steps: + # This pipeline usually are triggered by Zip-Nuget-Java-Nodejs Packaging Pipeline, + # The NPM_packages is from Android_Java_API_AAR_Packaging_QNN, not from RN_CI + - download: build + artifact: 'NPM_packages' + displayName: 'Download NPM_packages from Zip-Nuget-Java-Nodejs Packaging Pipeline Pipeline Artifact' - - task: CopyFiles@2 - inputs: - sourceFolder: '$(Pipeline.Workspace)\build\NPM_packages' - contents: onnxruntime-*.tgz - targetFolder: $(Build.ArtifactStagingDirectory)\node-artifacts - displayName: 'Copy onnxruntime-node Artifacts' + - task: CopyFiles@2 + inputs: + sourceFolder: '$(Pipeline.Workspace)\build\NPM_packages' + contents: onnxruntime-*.tgz + targetFolder: $(Build.ArtifactStagingDirectory)\node-artifacts + displayName: 'Copy onnxruntime-node Artifacts' - - task: PublishPipelineArtifact@0 - inputs: - artifactName: 'onnxruntime-node' - targetPath: '$(Build.ArtifactStagingDirectory)\node-artifacts' - displayName: 'Publish onnxruntime-node Pipeline Artifact' + - task: 1ES.PublishPipelineArtifact@1 + inputs: + artifactName: 'onnxruntime-node' + targetPath: '$(Build.ArtifactStagingDirectory)\node-artifacts' + displayName: 'Publish onnxruntime-node Pipeline Artifact' - - task: CopyFiles@2 - inputs: - sourceFolder: $(Build.SourcesDirectory)\tools\ci_build\github\js - contents: validate-npm-packages.py - targetFolder: $(Build.ArtifactStagingDirectory)\validation-scripts - displayName: 'Copy validation scripts' + - task: CopyFiles@2 + inputs: + sourceFolder: $(Build.SourcesDirectory)\tools\ci_build\github\js + contents: validate-npm-packages.py + targetFolder: $(Build.ArtifactStagingDirectory)\validation-scripts + displayName: 'Copy validation scripts' - - task: PublishPipelineArtifact@0 - inputs: - artifactName: 'validation_scripts' - targetPath: '$(Build.ArtifactStagingDirectory)\validation-scripts' - displayName: 'Publish validation scripts' + - task: 1ES.PublishPipelineArtifact@1 + inputs: + artifactName: 'validation_scripts' + targetPath: '$(Build.ArtifactStagingDirectory)\validation-scripts' + displayName: 'Publish validation scripts' diff --git a/tools/ci_build/github/azure-pipelines/nuget-cuda-publishing-pipeline.yml b/tools/ci_build/github/azure-pipelines/nuget-cuda-publishing-pipeline.yml index aeb250e1e0cbc..df4e328f49eaf 100644 --- a/tools/ci_build/github/azure-pipelines/nuget-cuda-publishing-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/nuget-cuda-publishing-pipeline.yml @@ -2,30 +2,44 @@ resources: pipelines: - pipeline: build source: 'CUDA-Zip-Nuget-Java-Packaging-Pipeline' - trigger: + trigger: branches: include: - main - rel-* branch: main + repositories: + - repository: 1esPipelines + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release parameters: - - name: isReleaseBuild - type: boolean - default: false +- name: isReleaseBuild + type: boolean + default: false variables: - - name: ArtifactFeed - ${{ if eq(parameters.isReleaseBuild, false) }}: - value: ORT-Nightly - ${{ else }}: - value: onnxruntime-cuda-12 +- name: ArtifactFeed + ${{ if eq(parameters.isReleaseBuild, false) }}: + value: ORT-Nightly + ${{ else }}: + value: onnxruntime-cuda-12 +extends: + # The pipeline extends the 1ES PT which will inject different SDL and compliance tasks. + # For non-production pipelines, use "Unofficial" as defined below. + # For productions pipelines, use "Official". + template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines + parameters: + sdl: + sourceAnalysisPool: + name: onnxruntime-Win-CPU-2022 + os: windows + stages: + - template: stages/nuget-cuda-publishing-stage.yml + parameters: + artifact_feed: $(ArtifactFeed) -stages: - - template: stages/nuget-cuda-publishing-stage.yml - parameters: - artifact_feed: $(ArtifactFeed) - - - template: stages/java-cuda-publishing-stage.yml - parameters: - artifact_feed: $(ArtifactFeed) \ No newline at end of file + - template: stages/java-cuda-publishing-stage.yml + parameters: + artifact_feed: $(ArtifactFeed) \ No newline at end of file diff --git a/tools/ci_build/github/azure-pipelines/nuget/templates/dml-vs-2022.yml b/tools/ci_build/github/azure-pipelines/nuget/templates/dml-vs-2022.yml index 8ab1eb2dd2fe4..130bc330d53f7 100644 --- a/tools/ci_build/github/azure-pipelines/nuget/templates/dml-vs-2022.yml +++ b/tools/ci_build/github/azure-pipelines/nuget/templates/dml-vs-2022.yml @@ -1,7 +1,6 @@ parameters: DoDebugBuild: 'true' # Unused. Use BuildConfigurations instead. - DoCompliance: 'false' BuildCommand: '' StageName: 'Windows_CI_Dev' DoNugetPack: 'false' @@ -144,7 +143,7 @@ stages: displayName: 'Create NuGet Package' failOnStderr: true - - task: PublishPipelineArtifact@0 + - task: 1ES.PublishPipelineArtifact@1 displayName: 'Publish Pipeline Artifact: ${{ parameters.ArtifactName }}' inputs: artifactName: ${{ parameters.ArtifactName }} @@ -182,7 +181,7 @@ stages: workingDirectory: '$(Build.SourcesDirectory)\js\node' displayName: 'Create NPM Package' - - task: PublishPipelineArtifact@0 + - task: 1ES.PublishPipelineArtifact@1 displayName: 'Publish Pipeline Artifact: ${{ parameters.ArtifactName }}' inputs: artifactName: ${{ parameters.ArtifactName }} @@ -208,17 +207,7 @@ stages: DisplayName: 'ESRP - Sign Node.js binding binaries' DoEsrp: ${{ parameters.DoEsrp }} Pattern: '*.node' - - task: PublishPipelineArtifact@1 + - task: 1ES.PublishPipelineArtifact@1 inputs: targetPath: '$(Build.SourcesDirectory)\js\node\bin\napi-v3\win32\${{ parameters.sln_platform }}' artifactName: 'drop-onnxruntime-nodejs-win-${{ parameters.sln_platform }}-dml' - - - - ${{ if eq(parameters['DoCompliance'], 'true') }}: - - template: ../../templates/compliance.yml - parameters : - msbuildPlatform: ${{ parameters.sln_platform }} - - - template: ../../templates/component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' diff --git a/tools/ci_build/github/azure-pipelines/nuget/templates/test_android.yml b/tools/ci_build/github/azure-pipelines/nuget/templates/test_android.yml new file mode 100644 index 0000000000000..c988a97b6a56c --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/nuget/templates/test_android.yml @@ -0,0 +1,63 @@ +parameters: + AgentPool : 'Win-CPU' + ArtifactSuffix: '' + SpecificArtifact: false + BuildId: '' + +stages: +- stage: NuGet_Test_Android + jobs: + - job: NuGet_Test_Android + workspace: + clean: all + pool: "${{ parameters.AgentPool }}" + + variables: + - name: OnnxRuntimeBuildDirectory + value: '$(Build.BinariesDirectory)' + + steps: + - task: NuGetToolInstaller@0 + displayName: Use Nuget 6.10.x + inputs: + versionSpec: 6.10.x + + - template: ../../templates/flex-downloadPipelineArtifact.yml + parameters: + StepName: 'Download Pipeline Artifact' + ArtifactName: drop-signed-nuget-${{ parameters.ArtifactSuffix }} + TargetPath: '$(Build.BinariesDirectory)\nuget-artifact' + SpecificArtifact: ${{ parameters.SpecificArtifact }} + BuildId: ${{ parameters.BuildId }} + + - template: get-nuget-package-version-as-variable.yml + parameters: + packageFolder: '$(Build.BinariesDirectory)\nuget-artifact' + + - task: PowerShell@2 + displayName: Install MAUI workloads + inputs: + targetType: 'inline' + script: | + dotnet workload install maui maui-android android + workingDirectory: '$(Build.SourcesDirectory)\csharp' + + - task: PowerShell@2 + displayName: Publish Android MAUI APK + inputs: + targetType: 'inline' + script: | + dotnet nuget add source $(Build.BinariesDirectory)\nuget-artifact --name local-nuget + dotnet publish -c Release --property:UsePrebuiltNativePackage=true --property:CurrentOnnxRuntimeVersion=$(NuGetPackageVersionNumber) -f net8.0-android + workingDirectory: '$(Build.SourcesDirectory)\csharp\test\Microsoft.ML.OnnxRuntime.Tests.MAUI' + + - task: PowerShell@2 + displayName: Run BrowserStack test + inputs: + targetType: 'inline' + script: | + dotnet test + workingDirectory: '$(Build.SourcesDirectory)\csharp\test\Microsoft.ML.OnnxRuntime.Tests.BrowserStack.Android' + env: + BROWSERSTACK_USERNAME: $(browserstack_username) + BROWSERSTACK_ACCESS_KEY: $(browserstack_access_key) diff --git a/tools/ci_build/github/azure-pipelines/nuget/templates/test_linux.yml b/tools/ci_build/github/azure-pipelines/nuget/templates/test_linux.yml index 8c6efe2c55e3a..ff598ce92ddb4 100644 --- a/tools/ci_build/github/azure-pipelines/nuget/templates/test_linux.yml +++ b/tools/ci_build/github/azure-pipelines/nuget/templates/test_linux.yml @@ -1,7 +1,7 @@ parameters: AgentPool: 'onnxruntime-Ubuntu2204-AMD-CPU' ArtifactSuffix: '' - NugetPackageName : '' + NugetPackageName: '' StageSuffix: 'CPU' # More Suffix is used to differentiate testing for GPU and GPU-Windows/GPU-Linux packages MoreSuffix: '' @@ -20,7 +20,9 @@ stages: workspace: clean: all timeoutInMinutes: 120 - pool: ${{ parameters.AgentPool }} + pool: + name: ${{ parameters.AgentPool }} + os: 'linux' variables: - template: ../../templates/common-variables.yml @@ -91,27 +93,23 @@ stages: " displayName: 'Run Package Test' - ${{ else }}: - - task: CmdLine@2 - displayName: 'Create symlink for test models' - inputs: - script: | - ln -sf /data/models $(Build.BinariesDirectory) - - task: Bash@3 - displayName: 'Run Package Test' - inputs: - targetType: filePath - filePath: '$(Build.SourcesDirectory)/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/runtest.sh' - arguments: '$(Build.BinariesDirectory)/nuget-artifact $(NuGetPackageVersionNumber)' - workingDirectory: $(Build.BinariesDirectory) - env: - OnnxRuntimeBuildDirectory: $(Build.BinariesDirectory) - DisableContribOps: $(DisableContribOps) - DisableMlOps: $(DisableMlOps) - IsReleaseBuild: $(IsReleaseBuild) - PACKAGENAME: ${{ parameters.NugetPackageName }} - - - template: ../../templates/component-governance-component-detection-steps.yml - parameters: - condition: 'always' + - task: CmdLine@2 + displayName: 'Create symlink for test models' + inputs: + script: | + ln -sf /data/models $(Build.BinariesDirectory) + - task: Bash@3 + displayName: 'Run Package Test' + inputs: + targetType: filePath + filePath: '$(Build.SourcesDirectory)/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/runtest.sh' + arguments: '$(Build.BinariesDirectory)/nuget-artifact $(NuGetPackageVersionNumber)' + workingDirectory: $(Build.BinariesDirectory) + env: + OnnxRuntimeBuildDirectory: $(Build.BinariesDirectory) + DisableContribOps: $(DisableContribOps) + DisableMlOps: $(DisableMlOps) + IsReleaseBuild: $(IsReleaseBuild) + PACKAGENAME: ${{ parameters.NugetPackageName }} - template: ../../templates/clean-agent-build-directory-step.yml diff --git a/tools/ci_build/github/azure-pipelines/nuget/templates/test_macos.yml b/tools/ci_build/github/azure-pipelines/nuget/templates/test_macos.yml index 07d21333270a8..5be0bfb7a3535 100644 --- a/tools/ci_build/github/azure-pipelines/nuget/templates/test_macos.yml +++ b/tools/ci_build/github/azure-pipelines/nuget/templates/test_macos.yml @@ -11,7 +11,9 @@ stages: workspace: clean: all pool: - vmImage: 'macOS-13' + name: 'Azure Pipelines' + image: 'macOS-14' + os: 'macOS' variables: - name: OnnxRuntimeBuildDirectory @@ -51,8 +53,4 @@ stages: DisableMlOps: $(DisableMlOps) IsReleaseBuild: $(IsReleaseBuild) - - template: ../../templates/component-governance-component-detection-steps.yml - parameters : - condition : 'always' - - template: ../../templates/clean-agent-build-directory-step.yml diff --git a/tools/ci_build/github/azure-pipelines/nuget/templates/test_win.yml b/tools/ci_build/github/azure-pipelines/nuget/templates/test_win.yml index 4842fcbd4dcfb..af2069a3512a5 100644 --- a/tools/ci_build/github/azure-pipelines/nuget/templates/test_win.yml +++ b/tools/ci_build/github/azure-pipelines/nuget/templates/test_win.yml @@ -118,8 +118,4 @@ stages: env: PACKAGENAME: ${{ parameters.NugetPackageName }} - - template: ../../templates/component-governance-component-detection-steps.yml - parameters : - condition : 'always' - - template: ../../templates/clean-agent-build-directory-step.yml diff --git a/tools/ci_build/github/azure-pipelines/post-merge-jobs.yml b/tools/ci_build/github/azure-pipelines/post-merge-jobs.yml index 6b421184c490e..2cecedb401724 100644 --- a/tools/ci_build/github/azure-pipelines/post-merge-jobs.yml +++ b/tools/ci_build/github/azure-pipelines/post-merge-jobs.yml @@ -4,7 +4,6 @@ parameters: type: string default: '12.2' values: - - 11.8 - 12.2 variables: @@ -427,7 +426,7 @@ stages: - job: IosDynamicFramework timeoutInMinutes: 120 pool: - vmImage: "macOS-13" + vmImage: "macOS-14" steps: - task: UsePythonVersion@0 @@ -463,7 +462,7 @@ stages: - job: IosMinimalTrainingBuild timeoutInMinutes: 120 pool: - vmImage: "macOS-13" + vmImage: "macOS-14" steps: - task: UsePythonVersion@0 diff --git a/tools/ci_build/github/azure-pipelines/publish-nuget.yml b/tools/ci_build/github/azure-pipelines/publish-nuget.yml index b78d586288ba3..ace0d62204551 100644 --- a/tools/ci_build/github/azure-pipelines/publish-nuget.yml +++ b/tools/ci_build/github/azure-pipelines/publish-nuget.yml @@ -8,35 +8,48 @@ resources: - main - rel-* branch: main - + repositories: + - repository: 1esPipelines + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release parameters: - - name: isReleaseBuild - type: boolean - default: false +- name: isReleaseBuild + type: boolean + default: false variables: - - name: ArtifactFeed - ${{ if eq(parameters.isReleaseBuild, false) }}: - value: ort-cuda-11-nightly - ${{ else }}: - value: onnxruntime-cuda-11 - -stages: - - template: templates/publish-nuget-steps.yml - parameters: - stage_name: 'Publish_NuGet_Package_And_Report' - include_cpu_ep: true - download_artifacts_steps: +- name: ArtifactFeed + ${{ if eq(parameters.isReleaseBuild, false) }}: + value: ORT-Nightly + ${{ else }}: + value: onnxruntime-cuda-12 +extends: + # The pipeline extends the 1ES PT which will inject different SDL and compliance tasks. + # For non-production pipelines, use "Unofficial" as defined below. + # For productions pipelines, use "Official". + template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines + parameters: + sdl: + sourceAnalysisPool: + name: onnxruntime-Win-CPU-2022 + os: windows + stages: + - template: templates/publish-nuget-steps.yml + parameters: + stage_name: 'Publish_NuGet_Package_And_Report' + include_cpu_ep: true + download_artifacts_steps: - download: build displayName: 'Download Pipeline Artifact - Signed NuGet Package' artifact: 'drop-signed-nuget-dml' - script: move "$(Pipeline.Workspace)\build\drop-signed-nuget-dml\*" $(Build.BinariesDirectory)\nuget-artifact\final-package - # Publish CUDA 11 Nuget/Java pkgs to ADO feed - - template: stages/nuget-cuda-publishing-stage.yml - parameters: - artifact_feed: $(ArtifactFeed) + # Publish CUDA 11 Nuget/Java pkgs to ADO feed + - template: stages/nuget-cuda-publishing-stage.yml + parameters: + artifact_feed: $(ArtifactFeed) - - template: stages/java-cuda-publishing-stage.yml - parameters: - artifact_feed: $(ArtifactFeed) + - template: stages/java-cuda-publishing-stage.yml + parameters: + artifact_feed: $(ArtifactFeed) diff --git a/tools/ci_build/github/azure-pipelines/py-cuda-alt-package-test-pipeline.yml b/tools/ci_build/github/azure-pipelines/py-cuda-alt-package-test-pipeline.yml deleted file mode 100644 index 960b59f93bee0..0000000000000 --- a/tools/ci_build/github/azure-pipelines/py-cuda-alt-package-test-pipeline.yml +++ /dev/null @@ -1,57 +0,0 @@ -resources: - pipelines: - - pipeline: build - source: 'Python CUDA ALT Packaging Pipeline' - trigger: true - branch: main # branch to pick the artifact, Used only for manual triggered pipeline runs for testing the pipeline itself - -stages: - # ****The following Stage depend on all previous tags. *** - # GPU resources are very limited, - # To utilize gpu resource more efficiently, run GPU job only after all cpus jobs succeed - - stage: Linux_Test_CUDA_Alt_x86_64_stage - dependsOn: - jobs: - - template: templates/py-packaging-linux-test-cuda.yml - parameters: - arch: 'x86_64' - machine_pool: 'Onnxruntime-Linux-GPU' - python_wheel_suffix: '_gpu' - timeout: 480 - docker_base_image: onnxruntimebuildcache.azurecr.io/internal/azureml/onnxruntime/build/cuda11_x64_almalinux8_gcc11:20250124.1 - cuda_version: '11.8' - - - stage: Republish_Wheels - dependsOn: - jobs: - - job: Python_Publishing_GPU - pool: 'onnxruntime-Ubuntu2204-AMD-CPU' - steps: - - checkout: none - - download: build - displayName: 'Download Pipeline Artifact - onnxruntime_gpu' - artifact: 'onnxruntime_gpu' - patterns: '*.whl' - - download: build - displayName: 'Download Pipeline Artifact - Win GPU 3.10' - artifact: 'win_gpu_wheel_3.10' - patterns: '*.whl' - - download: build - displayName: 'Download Pipeline Artifact - Win GPU 3.11' - artifact: 'win_gpu_wheel_3.11' - patterns: '*.whl' - - download: build - displayName: 'Download Pipeline Artifact - Win GPU 3.12' - artifact: 'win_gpu_wheel_3.12' - patterns: '*.whl' - - download: build - displayName: 'Download Pipeline Artifact - Win GPU 3.13' - artifact: 'win_gpu_wheel_3.13' - patterns: '*.whl' - - - script: find $(Pipeline.Workspace) -name \*win_amd64.whl -exec mv {} $(Pipeline.Workspace)/build/onnxruntime_gpu \; - displayName: 'Merge files together' - - - publish: $(Pipeline.Workspace)/build/onnxruntime_gpu - artifact: whl - displayName: Republish artifacts \ No newline at end of file diff --git a/tools/ci_build/github/azure-pipelines/py-cuda-alt-packaging-pipeline.yml b/tools/ci_build/github/azure-pipelines/py-cuda-alt-packaging-pipeline.yml deleted file mode 100644 index b4870db90a755..0000000000000 --- a/tools/ci_build/github/azure-pipelines/py-cuda-alt-packaging-pipeline.yml +++ /dev/null @@ -1,60 +0,0 @@ -trigger: none -resources: - repositories: - - repository: 1esPipelines - type: git - name: 1ESPipelineTemplates/1ESPipelineTemplates - ref: refs/tags/release -parameters: - - name: enable_linux_cuda - type: boolean - default: true - - - name: enable_windows_cuda - type: boolean - default: true - - - name: cmake_build_type - type: string - default: 'Release' - values: - - Debug - - Release - - RelWithDebInfo - - MinSizeRel -extends: - # The pipeline extends the 1ES PT which will inject different SDL and compliance tasks. - # For non-production pipelines, use "Unofficial" as defined below. - # For productions pipelines, use "Official". - template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines - parameters: - sdl: - componentgovernance: - ignoreDirectories: '$(Build.Repository.LocalPath)/cmake/external/emsdk/upstream/emscripten/tests,$(Build.Repository.LocalPath)/cmake/external/onnx/third_party/benchmark,$(Build.Repository.LocalPath)/cmake/external/onnx/third_party/pybind11,$(Build.Repository.LocalPath)/cmake/external/onnx/third_party/pybind11/tests,$(Build.Repository.LocalPath)/cmake/external/onnxruntime-extensions,$(Build.Repository.LocalPath)/js/react_native/e2e/node_modules,$(Build.Repository.LocalPath)/js/node_modules,$(Build.Repository.LocalPath)/onnxruntime-inference-examples,$(Build.SourcesDirectory)/cmake/external/emsdk/upstream/emscripten/tests,$(Build.SourcesDirectory)/cmake/external/onnx/third_party/benchmark,$(Build.SourcesDirectory)/cmake/external/onnx/third_party/pybind11,$(Build.SourcesDirectory)/cmake/external/onnx/third_party/pybind11/tests,$(Build.SourcesDirectory)/cmake/external/onnxruntime-extensions,$(Build.SourcesDirectory)/js/react_native/e2e/node_modules,$(Build.SourcesDirectory)/js/node_modules,$(Build.SourcesDirectory)/onnxruntime-inference-examples,$(Build.BinariesDirectory)' - alertWarningLevel: High - failOnAlert: false - verbosity: Normal - timeout: 3600 - tsa: - enabled: true - codeSignValidation: - enabled: true - break: true - policheck: - enabled: true - exclusionsFile: '$(Build.SourcesDirectory)\tools\ci_build\policheck_exclusions.xml' - codeql: - compiled: - enabled: false - justificationForDisabling: 'CodeQL is taking nearly 4 hours resulting in timeouts in our production pipelines' - pool: - name: 'onnxruntime-Win-CPU-2022' # Name of your hosted pool - os: windows # OS of the image. This value cannot be a variable. Allowed values: windows, linux, macOS - - stages: - - template: stages/py-gpu-packaging-stage.yml - parameters: - enable_linux_cuda: ${{ parameters.enable_linux_cuda }} - enable_windows_cuda: ${{ parameters.enable_windows_cuda }} - cmake_build_type: ${{ parameters.cmake_build_type }} - cuda_version: '11.8' diff --git a/tools/ci_build/github/azure-pipelines/py-cuda-publishing-pipeline.yml b/tools/ci_build/github/azure-pipelines/py-cuda-publishing-pipeline.yml index e4499705efdf5..230c391c00ebd 100644 --- a/tools/ci_build/github/azure-pipelines/py-cuda-publishing-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/py-cuda-publishing-pipeline.yml @@ -7,7 +7,11 @@ resources: include: - main branch: main - + repositories: + - repository: 1esPipelines + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release parameters: - name: isReleaseBuild type: boolean @@ -20,7 +24,17 @@ variables: ${{ else }}: value: onnxruntime-cuda-12 -stages: -- template: stages/py-cuda-publishing-stage.yml +extends: + # The pipeline extends the 1ES PT which will inject different SDL and compliance tasks. + # For non-production pipelines, use "Unofficial" as defined below. + # For productions pipelines, use "Official". + template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines parameters: - artifact_feed: $(ArtifactFeed) \ No newline at end of file + sdl: + sourceAnalysisPool: + name: onnxruntime-Win-CPU-2022 + os: windows + stages: + - template: stages/py-cuda-publishing-stage.yml + parameters: + artifact_feed: $(ArtifactFeed) \ No newline at end of file diff --git a/tools/ci_build/github/azure-pipelines/py-package-test-pipeline.yml b/tools/ci_build/github/azure-pipelines/py-package-test-pipeline.yml index a0e49692220f9..01c1366107292 100644 --- a/tools/ci_build/github/azure-pipelines/py-package-test-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/py-package-test-pipeline.yml @@ -29,12 +29,14 @@ stages: parameters: job_name: Test_MAC_Wheels machine_pool: - vmImage: 'macOS-13' + vmImage: 'macOS-14' itemPattern: '*/*mac*x86_64.whl' + arch: 'x86_64' - template: templates/py-package-smoking-test.yml parameters: job_name: Test_LINUX_x86_64_Wheels itemPattern: '*/*manylinux*x86_64.whl' + arch: 'x86_64' machine_pool: name: 'onnxruntime-Ubuntu2204-AMD-CPU' diff --git a/tools/ci_build/github/azure-pipelines/py-packaging-pipeline.yml b/tools/ci_build/github/azure-pipelines/py-packaging-pipeline.yml index 01d30d0e1ba86..41549287cd3ab 100644 --- a/tools/ci_build/github/azure-pipelines/py-packaging-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/py-packaging-pipeline.yml @@ -50,30 +50,46 @@ parameters: displayName: 'Linux packages cmake build type. Linux Only.' default: 'Release' values: - - Debug - - Release - - RelWithDebInfo - - MinSizeRel + - Debug + - Release + - RelWithDebInfo + - MinSizeRel # Only applies to QNN packages. - name: qnn_sdk_version type: string displayName: 'QNN SDK version. Only for QNN packages.' - default: 2.31.0.250130 + default: 2.32.0.250228 trigger: none -stages: -- template: stages/py-cpu-packaging-stage.yml +resources: + repositories: + - repository: 1esPipelines + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release +extends: + # The pipeline extends the 1ES PT which will inject different SDL and compliance tasks. + # For non-production pipelines, use "Unofficial" as defined below. + # For productions pipelines, use "Official". + template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines parameters: - enable_linux_cpu: ${{ parameters.enable_linux_cpu }} - enable_windows_cpu: ${{ parameters.enable_windows_cpu }} - enable_mac_cpu: ${{ parameters.enable_mac_cpu }} - enable_linux_arm: ${{ parameters.enable_linux_arm }} - enable_windows_arm64_qnn: ${{ parameters.enable_windows_arm64_qnn }} - enable_windows_arm64ec_qnn: ${{ parameters.enable_windows_arm64ec_qnn }} - enable_windows_x64_qnn: ${{ parameters.enable_windows_x64_qnn }} - enable_linux_x64_qnn: ${{ parameters.enable_linux_x64_qnn }} - build_py_parameters: ${{ parameters.build_py_parameters }} - cmake_build_type: ${{ parameters.cmake_build_type }} - qnn_sdk_version: ${{ parameters.qnn_sdk_version }} + sdl: + sourceAnalysisPool: + name: onnxruntime-Win-CPU-2022 + os: windows + stages: + - template: stages/py-cpu-packaging-stage.yml + parameters: + enable_linux_cpu: ${{ parameters.enable_linux_cpu }} + enable_windows_cpu: ${{ parameters.enable_windows_cpu }} + enable_mac_cpu: ${{ parameters.enable_mac_cpu }} + enable_linux_arm: ${{ parameters.enable_linux_arm }} + enable_windows_arm64_qnn: ${{ parameters.enable_windows_arm64_qnn }} + enable_windows_arm64ec_qnn: ${{ parameters.enable_windows_arm64ec_qnn }} + enable_windows_x64_qnn: ${{ parameters.enable_windows_x64_qnn }} + enable_linux_x64_qnn: ${{ parameters.enable_linux_x64_qnn }} + build_py_parameters: ${{ parameters.build_py_parameters }} + cmake_build_type: ${{ parameters.cmake_build_type }} + qnn_sdk_version: ${{ parameters.qnn_sdk_version }} diff --git a/tools/ci_build/github/azure-pipelines/qnn-ep-nuget-packaging-pipeline.yml b/tools/ci_build/github/azure-pipelines/qnn-ep-nuget-packaging-pipeline.yml index 055ef58e4524a..fedabba9083e6 100644 --- a/tools/ci_build/github/azure-pipelines/qnn-ep-nuget-packaging-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/qnn-ep-nuget-packaging-pipeline.yml @@ -2,7 +2,7 @@ parameters: - name: QnnSdk displayName: QNN SDK Version type: string - default: 2.31.0.250130 + default: 2.32.0.250228 - name: build_config displayName: Build Configuration @@ -29,108 +29,58 @@ parameters: displayName: Pipeline BuildId, you could find it in the URL type: string default: '0' - -stages: - -- template: templates/qnn-ep-win.yml - parameters: - qnn_ep_build_pool_name: 'Onnxruntime-QNNEP-Windows-2022-CPU' - QnnSdk: ${{ parameters.QnnSdk }} - IsReleaseBuild: ${{ parameters.IsReleaseBuild }} - DoEsrp: ${{ parameters.DoEsrp }} - ArtifactName: 'drop-nuget-qnn-x64' - StageName: 'OnnxRuntime_QNN_Nuget_Win_x64' - build_config: ${{ parameters.build_config }} - -- template: templates/qnn-ep-win.yml +resources: + repositories: + - repository: 1esPipelines + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release +extends: + # The pipeline extends the 1ES PT which will inject different SDL and compliance tasks. + # For non-production pipelines, use "Unofficial" as defined below. + # For productions pipelines, use "Official". + template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines parameters: - qnn_ep_build_pool_name: 'Onnxruntime-QNNEP-Windows-2022-CPU' - QnnSdk: ${{ parameters.QnnSdk }} - IsReleaseBuild: ${{ parameters.IsReleaseBuild }} - DoEsrp: ${{ parameters.DoEsrp }} - ArtifactName: 'drop-nuget-qnn-arm64' - buildParameter: '--arm64' - buildPlatform: 'ARM64' - buildArch: 'ARM64' - StageName: 'OnnxRuntime_QNN_Nuget_Win_Arm64' - build_config: ${{ parameters.build_config }} - -- stage: NuGet_Packaging_QNN - pool: 'Onnxruntime-QNNEP-Windows-2022-CPU' - dependsOn: - - OnnxRuntime_QNN_Nuget_Win_x64 - - OnnxRuntime_QNN_Nuget_Win_Arm64 - condition: succeeded() - jobs: - - job: NuGet_Packaging_QNN - workspace: - clean: all - steps: - - task: DownloadPipelineArtifact@0 - displayName: 'Download Pipeline Artifact - QNN NuGet x64' - inputs: - artifactName: 'drop-nuget-qnn-x64' - targetPath: '$(Build.BinariesDirectory)/nuget-artifact-x64' - - - task: DownloadPipelineArtifact@0 - displayName: 'Download Pipeline Artifact - QNN NuGet arm64' - inputs: - artifactName: 'drop-nuget-qnn-arm64' - targetPath: '$(Build.BinariesDirectory)/nuget-artifact-arm64' - - - task: PowerShell@2 - displayName: 'Bundle NuGet' - inputs: - targetType: 'inline' - script: | - - $x64_nupkgs = (Get-ChildItem $(Build.BinariesDirectory)/nuget-artifact-x64 -Filter Microsoft.ML.OnnxRuntime.QNN*.nupkg -Recurse) - $nuget_package_name = $x64_nupkgs[0].Name - $x64_nuget_package = $x64_nupkgs[0].FullName - - $nupkg_unzipped_directory = [System.IO.Path]::Combine($Env:BUILD_ARTIFACTSTAGINGDIRECTORY, 'nuget_unzip_merged', [System.IO.Path]::GetFileNameWithoutExtension($nuget_package_name)) - - $x64_unzip_cmd = "7z.exe x $x64_nuget_package -y -o$nupkg_unzipped_directory" - Invoke-Expression -Command $x64_unzip_cmd - - $arm64_nupkgs = (Get-ChildItem $(Build.BinariesDirectory)/nuget-artifact-arm64 -Filter Microsoft.ML.OnnxRuntime.QNN*.nupkg -Recurse) - $arm64_nuget_package = $arm64_nupkgs[0].FullName + sdl: + sourceAnalysisPool: + name: onnxruntime-Win-CPU-2022 + os: windows + stages: - $arm64_unzip_cmd = "7z.exe x $arm64_nuget_package -y -o$nupkg_unzipped_directory" - Invoke-Expression -Command $arm64_unzip_cmd - - $merged_nuget_path = [System.IO.Path]::Combine($Env:BUILD_ARTIFACTSTAGINGDIRECTORY, 'nuget-artifact-merged') - if (!(Test-Path $merged_nuget_path)) { - New-Item -Path $merged_nuget_path -ItemType Directory - } - - $merged_zip = [System.IO.Path]::Combine($merged_nuget_path, 'qnn_nuget.zip') - $zip_cmd = "7z.exe a -r $merged_zip $nupkg_unzipped_directory/*" - Invoke-Expression -Command $zip_cmd - - $merged_nuget = [System.IO.Path]::Combine($merged_nuget_path, $nuget_package_name) - move $merged_zip $merged_nuget - workingDirectory: $(Build.BinariesDirectory) - - - template: templates/esrp_nuget.yml + - template: templates/qnn-ep-win.yml parameters: - DisplayName: 'ESRP - sign NuGet package' - FolderPath: '$(Build.ArtifactStagingDirectory)/nuget-artifact-merged' + qnn_ep_build_pool_name: 'Onnxruntime-QNNEP-Windows-2022-CPU' + QnnSdk: ${{ parameters.QnnSdk }} + IsReleaseBuild: ${{ parameters.IsReleaseBuild }} DoEsrp: ${{ parameters.DoEsrp }} + ArtifactName: 'drop-nuget-qnn-x64' + StageName: 'OnnxRuntime_QNN_Nuget_Win_x64' + build_config: ${{ parameters.build_config }} - - task: PublishPipelineArtifact@0 - displayName: 'Publish Pipeline NuGet Artifact' - inputs: - artifactName: 'drop-signed-nuget-qnn' - targetPath: '$(Build.ArtifactStagingDirectory)/nuget-artifact-merged' + - template: templates/qnn-ep-win.yml + parameters: + qnn_ep_build_pool_name: 'Onnxruntime-QNNEP-Windows-2022-CPU' + QnnSdk: ${{ parameters.QnnSdk }} + IsReleaseBuild: ${{ parameters.IsReleaseBuild }} + DoEsrp: ${{ parameters.DoEsrp }} + ArtifactName: 'drop-nuget-qnn-arm64' + buildParameter: '--arm64' + buildPlatform: 'ARM64' + buildArch: 'ARM64' + StageName: 'OnnxRuntime_QNN_Nuget_Win_Arm64' + build_config: ${{ parameters.build_config }} + + - template: stages/nuget-qnn-packaging-stage.yml + parameters: + DoEsrp: ${{ parameters.DoEsrp }} -- template: templates/publish-nuget-steps.yml - parameters: - download_artifacts_steps: - - template: templates/flex-downloadPipelineArtifact.yml - parameters: - StepName: 'Download Pipeline Artifact - Signed NuGet Qnn Package' - ArtifactName: 'drop-signed-nuget-qnn' - targetPath: '$(Build.BinariesDirectory)/nuget-artifact/final-package' - SpecificArtifact: ${{ parameters.specificArtifact }} - BuildId: ${{ parameters.BuildId }} + - template: templates/publish-nuget-steps.yml + parameters: + download_artifacts_steps: + - template: templates/flex-downloadPipelineArtifact.yml + parameters: + StepName: 'Download Pipeline Artifact - Signed NuGet Qnn Package' + ArtifactName: 'drop-signed-nuget-qnn' + targetPath: '$(Build.BinariesDirectory)/nuget-artifact/final-package' + SpecificArtifact: ${{ parameters.specificArtifact }} + BuildId: ${{ parameters.BuildId }} diff --git a/tools/ci_build/github/azure-pipelines/rocm-nuget-packaging-pipeline.yml b/tools/ci_build/github/azure-pipelines/rocm-nuget-packaging-pipeline.yml deleted file mode 100644 index f7f5c7b1494e8..0000000000000 --- a/tools/ci_build/github/azure-pipelines/rocm-nuget-packaging-pipeline.yml +++ /dev/null @@ -1,339 +0,0 @@ -parameters: -- name: RunOnnxRuntimeTests - displayName: Run Tests? - type: boolean - default: true - -- name: UseIncreasedTimeoutForTests - displayName: Increase timeout for tests? Set it to false if you are doing an Onnx Runtime release. - type: boolean - default: false - -- name: DoCompliance - displayName: Run Compliance Tasks? - type: boolean - default: true - -- name: DoEsrp - displayName: Run code sign tasks? Must be true if you are doing an ONNX Runtime release - type: boolean - default: true - -- name: IsReleaseBuild - displayName: Is a release build? Set it to true if you are doing an ONNX Runtime release. - type: boolean - default: false - -- name: PreReleaseVersionSuffixString - displayName: Suffix added to pre-release package version. Only used if IsReleaseBuild is true. Denotes the type of pre-release package. - type: string - values: - - alpha - - beta - - rc - - none - default: none - -- name: PreReleaseVersionSuffixNumber - displayName: Number added to pre-release package version. Only used if IsReleaseBuild is true. Denotes the sequence of a pre-release package. - type: number - default: 0 - -# these 2 parameters are used for debugging. -- name: SpecificArtifact - displayName: Use Specific Artifact (Debugging only) - type: boolean - default: false - -- name: BuildId - displayName: Pipeline BuildId, you could find it in the URL - type: string - default: '0' - -- name: NugetPackageSuffix - displayName: Suffix to append to nuget package - type: string - default: 'NONE' - -resources: - repositories: - - repository: onnxruntime-inference-examples # The name used to reference this repository in the checkout step - type: github - endpoint: ort-examples - name: microsoft/onnxruntime-inference-examples - - repository: manylinux - type: Github - endpoint: Microsoft - name: pypa/manylinux - ref: 5eda9aded5462201e6310105728d33016e637ea7 - -variables: -- name: ReleaseVersionSuffix - value: '' - -stages: -- template: stages/set_packaging_variables_stage.yml - parameters: - IsReleaseBuild: ${{ parameters.IsReleaseBuild }} - PreReleaseVersionSuffixString: ${{ parameters.PreReleaseVersionSuffixString }} - PreReleaseVersionSuffixNumber: ${{ parameters.PreReleaseVersionSuffixNumber }} - -# ROCm -- stage: Linux_C_API_Packaging_ROCm_x64 - dependsOn: [] - jobs: - - job: Linux_C_API_Packaging_ROCm_x64 - workspace: - clean: all - timeoutInMinutes: 480 - pool: onnxruntime-Ubuntu2204-AMD-CPU - variables: - RocmVersion: '6.2' - RocmVersionPatchSuffix: '' - steps: - - checkout: self # due to checkout multiple repos, the root directory is $(Build.SourcesDirectory)/onnxruntime - submodules: recursive - - checkout: manylinux # due to checkout multiple repos, the root directory is $(Build.SourcesDirectory)/manylinux, for get-docker-image-steps.yml - submodules: false - - # get-docker-image-steps.yml will move the $(Build.SourcesDirectory)/manylinux into $(Build.SourcesDirectory)/onnxruntime, - # then rename $(Build.SourcesDirectory)/onnxruntime as $(Build.SourcesDirectory) - - template: templates/get-docker-image-steps.yml - parameters: - Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_rocm - Context: tools/ci_build/github/linux/docker - DockerBuildArgs: >- - --build-arg INSTALL_DEPS_EXTRA_ARGS=-tmur - --build-arg BUILD_UID=$(id -u) - --network=host --build-arg POLICY=manylinux_2_28 --build-arg PLATFORM=x86_64 - --build-arg ROCM_VERSION=$(RocmVersion)$(RocmVersionPatchSuffix) - --build-arg DEVTOOLSET_ROOTPATH=/opt/rh/gcc-toolset-12/root - --build-arg PREPEND_PATH=/opt/rh/gcc-toolset-12/root/usr/bin: - --build-arg LD_LIBRARY_PATH_ARG=/opt/rh/gcc-toolset-12/root/usr/lib64:/opt/rh/gcc-toolset-12/root/usr/lib:/opt/rh/gcc-toolset-12/root/usr/lib64/dyninst:/opt/rh/gcc-toolset-12/root/usr/lib/dyninst:/usr/local/lib64:/usr/local/lib - Repository: onnxruntimetrainingrocmbuild-rocm$(RocmVersion) - CheckOutManyLinux: true - - - template: templates/set-version-number-variables-step.yml - - - task: Bash@3 - displayName: 'Build' - inputs: - targetType: filePath - filePath: tools/ci_build/github/linux/build_rocm_c_api_package.sh - arguments: >- - -S $(Build.SourcesDirectory) - -B $(Build.BinariesDirectory) - -V $(RocmVersion) - -I onnxruntimetrainingrocmbuild-rocm$(RocmVersion) - -P python3.10 - - - script: | - set -e -x - mkdir $(Build.ArtifactStagingDirectory)/testdata - cp $(Build.BinariesDirectory)/Release/libcustom_op_library.so* $(Build.ArtifactStagingDirectory)/testdata - ls -al $(Build.ArtifactStagingDirectory) - displayName: 'Create Artifacts for CustomOp' # libcustom_op_library.so from cpu build is built with fp8, ROCm does not support it. - - - template: templates/c-api-artifacts-package-and-publish-steps-posix.yml - parameters: - buildConfig: 'Release' - artifactName: 'onnxruntime-linux-x64-rocm-$(OnnxRuntimeVersion)' - artifactNameNoVersionString: 'onnxruntime-linux-x64-rocm' - libraryName: 'libonnxruntime.so.$(OnnxRuntimeVersion)' - - - template: templates/component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' - - template: templates/clean-agent-build-directory-step.yml - -- stage: NuGet_Packaging_ROCm - dependsOn: - - Setup - - Linux_C_API_Packaging_ROCm_x64 - condition: succeeded() - jobs: - - job: NuGet_Packaging_ROCm - workspace: - clean: all - # we need to use a 2022 pool to create the nuget package with MAUI targets. - # VS2019 has no support for net6/MAUI and we need to use msbuild (from the VS install) to do the packing - pool: 'Onnxruntime-Win-CPU-2022' - variables: - breakCodesignValidationInjection: ${{ parameters.DoEsrp }} - ReleaseVersionSuffix: $[stageDependencies.Setup.Set_Variables.outputs['Set_Release_Version_Suffix.ReleaseVersionSuffix']] - BuildDate : $[stageDependencies.Setup.Set_Variables.outputs['Set_Build_Date.BuildDate']] - BuildTime : $[stageDependencies.Setup.Set_Variables.outputs['Set_Build_Time.BuildTime']] - - steps: - - checkout: self - submodules: true - fetchDepth: 1 - - - template: templates/flex-downloadPipelineArtifact.yml - parameters: - StepName: 'Download Pipeline Artifact - NuGet' - ArtifactName: 'onnxruntime-linux-x64-rocm' - targetPath: '$(Build.BinariesDirectory)/nuget-artifact' - SpecificArtifact: ${{ parameters.specificArtifact }} - BuildId: ${{ parameters.BuildId }} - - - task: PowerShell@2 - displayName: 'Reconstruct Build Directory' - inputs: - targetType: inline - script: | - Get-ChildItem $(Build.BinariesDirectory)\nuget-artifact -Filter *.tgz | % { - # *.tar will be created after *.tgz is extracted - $cmd = "7z.exe x $($_.FullName) -y -o$(Build.BinariesDirectory)\nuget-artifact" - Write-Output $cmd - Invoke-Expression -Command $cmd - } - - Get-ChildItem $(Build.BinariesDirectory)\nuget-artifact -Filter *.tar | % { - $cmd = "7z.exe x $($_.FullName) -y -o$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\nuget-artifacts" - Write-Output $cmd - Invoke-Expression -Command $cmd - } - - $ort_dirs = Get-ChildItem -Path $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\nuget-artifacts\onnxruntime-* -Directory - foreach ($ort_dir in $ort_dirs) - { - $dirname = Split-Path -Path $ort_dir -Leaf - $dirname = $dirname.SubString(0, $dirname.LastIndexOf('-')) - Write-Output "Renaming $ort_dir to $dirname" - Rename-Item -Path $ort_dir -NewName $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\nuget-artifacts\$dirname - } - - Copy-Item -Path $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\nuget-artifacts\onnxruntime-linux-x64-rocm\lib\* -Destination $(Build.BinariesDirectory)\RelWithDebInfo - - - script: | - tree /F - workingDirectory: '$(Build.BinariesDirectory)' - displayName: 'Inspect Build Binaries Directory' - - - script: | - mklink /D /J models C:\local\models - workingDirectory: '$(Build.BinariesDirectory)' - displayName: 'Create models link' - - - task: NuGetToolInstaller@0 - displayName: Use Nuget 6.10.x - inputs: - versionSpec: 6.10.x - - - task: MSBuild@1 - displayName: 'Restore NuGet Packages and create project.assets.json' - inputs: - solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.sln' - platform: 'Any CPU' - configuration: RelWithDebInfo - msbuildArguments: '-t:restore -p:OrtPackageId="Microsoft.ML.OnnxRuntime.ROCm"' - workingDirectory: '$(Build.SourcesDirectory)\csharp' - - - task: MSBuild@1 - displayName: 'Build C# bindings' - inputs: - solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.sln' - platform: 'Any CPU' - configuration: RelWithDebInfo - msbuildArguments: > - -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" - -p:OrtPackageId="Microsoft.ML.OnnxRuntime.ROCm" - -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} - -p:ReleaseVersionSuffix=$(ReleaseVersionSuffix) - -p:IsLinuxBuild=true - -p:IsWindowsBuild=false - -p:IsMacOSBuild=false - workingDirectory: '$(Build.SourcesDirectory)\csharp' - - - template: templates/win-esrp-dll.yml - parameters: - FolderPath: '$(Build.SourcesDirectory)\csharp\src\Microsoft.ML.OnnxRuntime\bin\RelWithDebInfo' - DisplayName: 'ESRP - Sign C# dlls' - DoEsrp: ${{ parameters.DoEsrp }} - - - task: UsePythonVersion@0 - displayName: 'Use Python' - inputs: - versionSpec: 3.12 - - - task: MSBuild@1 - displayName: 'Build Nuget Packages' - inputs: - solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.proj' - configuration: RelWithDebInfo - platform: 'Any CPU' - msbuildArguments: > - -t:CreatePackage - -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" - -p:OrtPackageId=Microsoft.ML.OnnxRuntime.ROCm - -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} - -p:ReleaseVersionSuffix=$(ReleaseVersionSuffix) - -p:CurrentTime=$(BuildTime) - -p:CurrentDate=$(BuildDate) - workingDirectory: '$(Build.SourcesDirectory)\csharp' - - - task: CopyFiles@2 - displayName: 'Copy nuget packages to: $(Build.ArtifactStagingDirectory)' - inputs: - SourceFolder: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo' - Contents: '*.snupkg' - TargetFolder: '$(Build.ArtifactStagingDirectory)' - - - task: CopyFiles@2 - displayName: 'Copy nuget packages to: $(Build.ArtifactStagingDirectory)' - inputs: - SourceFolder: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo' - Contents: '*.nupkg' - TargetFolder: '$(Build.ArtifactStagingDirectory)' - - - task: CopyFiles@2 - displayName: 'Copy nuget packages to: $(Build.ArtifactStagingDirectory)' - inputs: - SourceFolder: '$(Build.SourcesDirectory)\csharp\src\Microsoft.ML.OnnxRuntime\bin\RelWithDebInfo' - Contents: '*.nupkg' - TargetFolder: '$(Build.ArtifactStagingDirectory)' - - - template: templates/esrp_nuget.yml - parameters: - DisplayName: 'ESRP - sign NuGet package' - FolderPath: '$(Build.ArtifactStagingDirectory)' - DoEsrp: ${{ parameters.DoEsrp }} - - - template: templates/validate-package.yml - parameters: - PackageType: 'nuget' - PackagePath: '$(Build.ArtifactStagingDirectory)' - PackageName: 'Microsoft.ML.OnnxRuntime.*nupkg' - PlatformsSupported: 'linux-x64' - VerifyNugetSigning: false - - - task: PublishPipelineArtifact@0 - displayName: 'Publish Pipeline NuGet Artifact' - inputs: - artifactName: 'drop-signed-nuget-ROCm' - targetPath: '$(Build.ArtifactStagingDirectory)' - - - task: MSBuild@1 - displayName: 'Clean C#' - inputs: - solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.sln' - platform: 'Any CPU' - configuration: RelWithDebInfo - msbuildArguments: '-t:Clean -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId=Microsoft.ML.OnnxRuntime.ROCm' - workingDirectory: '$(Build.SourcesDirectory)\csharp' - - - template: templates/component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' - - -- template: nuget/templates/test_linux.yml - parameters: - AgentPool: AMD-GPU - ArtifactSuffix: 'ROCm' - StageSuffix: 'ROCm' - NugetPackageName: 'Microsoft.ML.OnnxRuntime.ROCm' - SpecificArtifact: ${{ parameters.specificArtifact }} - CustomOpArtifactName: 'onnxruntime-linux-x64-rocm' - BuildId: ${{ parameters.BuildId }} diff --git a/tools/ci_build/github/azure-pipelines/rocm-publish-nuget-pipeline.yml b/tools/ci_build/github/azure-pipelines/rocm-publish-nuget-pipeline.yml deleted file mode 100644 index 1d2393d8f96d5..0000000000000 --- a/tools/ci_build/github/azure-pipelines/rocm-publish-nuget-pipeline.yml +++ /dev/null @@ -1,21 +0,0 @@ -resources: - pipelines: - - pipeline: build - source: 'Nuget ROCM Packaging pipeline' - trigger: - branches: - include: - - main - - rel-* - branch: main - -# ROCm -stages: -- template: templates/publish-nuget-steps.yml - parameters: - stage_name: 'Publish_ROCM_NuGet_Package' - download_artifacts_steps: - - download: build - displayName: 'Download Pipeline Artifact - Signed NuGet Package' - artifact: 'drop-signed-nuget-ROCm' - - script: move "$(Pipeline.Workspace)\build\drop-signed-nuget-ROCm\*" $(Build.BinariesDirectory)\nuget-artifact\final-package diff --git a/tools/ci_build/github/azure-pipelines/stages/c-api-linux-cpu-stage.yml b/tools/ci_build/github/azure-pipelines/stages/c-api-linux-cpu-stage.yml new file mode 100644 index 0000000000000..ee46d5dac2ff8 --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/stages/c-api-linux-cpu-stage.yml @@ -0,0 +1,11 @@ +stages: +- stage: Linux_C_API_Packaging_CPU + dependsOn: [] + jobs: + - template: ../templates/c-api-linux-cpu.yml + parameters: + OnnxruntimeArch: 'x64' + OnnxruntimeNodejsBindingArch: 'x64' + PoolName: 'onnxruntime-Ubuntu2204-AMD-CPU' + PackageJava: false + PackageNodeJS: false \ No newline at end of file diff --git a/tools/ci_build/github/azure-pipelines/stages/download-java-tools-stage.yml b/tools/ci_build/github/azure-pipelines/stages/download-java-tools-stage.yml index 49d73c699e7b7..1cc3e2def327f 100644 --- a/tools/ci_build/github/azure-pipelines/stages/download-java-tools-stage.yml +++ b/tools/ci_build/github/azure-pipelines/stages/download-java-tools-stage.yml @@ -5,6 +5,7 @@ stages: - job: Download_Java_Tools pool: name: 'onnxruntime-Ubuntu2204-AMD-CPU' + os: linux steps: - checkout: none - task: CmdLine@2 @@ -17,11 +18,9 @@ stages: wget --tries=3 https://oss.sonatype.org/service/local/repositories/releases/content/com/google/protobuf/protobuf-java/3.21.7/protobuf-java-3.21.7.jar -P ./ popd workingDirectory: '$(Agent.TempDirectory)' - - task: PublishPipelineArtifact@1 + + - task: 1ES.PublishPipelineArtifact@1 displayName: 'Publish Pipeline Java Tools Artifact' inputs: targetPath: '$(Agent.TempDirectory)/java-tools' - artifact: 'onnxruntime-java-tools' - - template: ../templates/component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' \ No newline at end of file + artifact: 'onnxruntime-java-tools' \ No newline at end of file diff --git a/tools/ci_build/github/azure-pipelines/stages/java-cuda-packaging-stage.yml b/tools/ci_build/github/azure-pipelines/stages/java-cuda-packaging-stage.yml index 82ac898906b9e..617c00b5fa592 100644 --- a/tools/ci_build/github/azure-pipelines/stages/java-cuda-packaging-stage.yml +++ b/tools/ci_build/github/azure-pipelines/stages/java-cuda-packaging-stage.yml @@ -73,15 +73,12 @@ stages: SourceFolder: '$(Build.BinariesDirectory)\java-artifact\onnxruntime-java-win-x64' TargetFolder: '$(Build.ArtifactStagingDirectory)' - - task: PublishPipelineArtifact@1 + - task: 1ES.PublishPipelineArtifact@1 displayName: 'Publish Pipeline Artifact' inputs: - targetPath: '$(Build.ArtifactStagingDirectory)' + path: '$(Build.ArtifactStagingDirectory)' artifact: 'onnxruntime-java-gpu' - - template: ../templates/component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' - job: Final_Jar_Testing_Windows_GPU dependsOn: Jar_Packaging_GPU @@ -127,16 +124,14 @@ stages: popd java -DUSE_CUDA=1 -jar junit-platform-console-standalone-1.6.2.jar -cp .;.\test;protobuf-java-3.21.7.jar;onnxruntime_gpu-$(OnnxRuntimeVersion).jar --scan-class-path --fail-if-no-tests --disable-banner workingDirectory: '$(Build.BinariesDirectory)\final-jar' - - - template: ../templates/component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' - job: Final_Jar_Testing_Linux_GPU dependsOn: Jar_Packaging_GPU workspace: clean: all - pool: 'Onnxruntime-Linux-GPU' + pool: + name: 'Onnxruntime-Linux-GPU-A10' + os: linux variables: - name: runCodesignValidationInjection value: false @@ -180,7 +175,3 @@ stages: onnxruntimeubi8packagestest \ /bin/bash /onnxruntime_src/tools/ci_build/github/linux/java_linux_final_test.sh -r /build -v $(OnnxRuntimeVersion) displayName: 'Test' - - - template: ../templates/component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' diff --git a/tools/ci_build/github/azure-pipelines/stages/java-cuda-publishing-stage.yml b/tools/ci_build/github/azure-pipelines/stages/java-cuda-publishing-stage.yml index 946d651b795d4..8f14b315d899d 100644 --- a/tools/ci_build/github/azure-pipelines/stages/java-cuda-publishing-stage.yml +++ b/tools/ci_build/github/azure-pipelines/stages/java-cuda-publishing-stage.yml @@ -11,7 +11,8 @@ stages: condition: ${{ or(eq(parameters.artifact_feed, 'onnxruntime-cuda-11'), eq(parameters.artifact_feed, 'onnxruntime-cuda-12')) }} workspace: clean: all - pool: 'onnxruntime-Win-CPU-2022' + pool: + name: 'onnxruntime-Win-CPU-2022' variables: - name: SYSTEM_ACCESSTOKEN value: $(System.AccessToken) diff --git a/tools/ci_build/github/azure-pipelines/stages/jobs/py-linux-cuda-package-test-job.yml b/tools/ci_build/github/azure-pipelines/stages/jobs/py-linux-cuda-package-test-job.yml index 85366ffc28b3a..4e42afe0da96e 100644 --- a/tools/ci_build/github/azure-pipelines/stages/jobs/py-linux-cuda-package-test-job.yml +++ b/tools/ci_build/github/azure-pipelines/stages/jobs/py-linux-cuda-package-test-job.yml @@ -2,9 +2,8 @@ parameters: - name: CudaVersion displayName: 'CUDA version' type: string - default: '11.8' + default: '12.2' values: - - 11.8 - 12.2 - name: machine_pool type: string @@ -114,6 +113,3 @@ jobs: targetType: filePath filePath: tools/ci_build/github/linux/run_python_dockertest.sh arguments: -d GPU -c ${{parameters.cmake_build_type}} -i onnxruntimecuda${{ replace(parameters.CudaVersion, '.', '') }}xtrt86buildx86_64 -u 12.2 - - template: ../../templates/component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' diff --git a/tools/ci_build/github/azure-pipelines/stages/jobs/react-natvie-andriod-e2e-test-job.yml b/tools/ci_build/github/azure-pipelines/stages/jobs/react-natvie-andriod-e2e-test-job.yml index 638da2866bdef..5f5628a4326d3 100644 --- a/tools/ci_build/github/azure-pipelines/stages/jobs/react-natvie-andriod-e2e-test-job.yml +++ b/tools/ci_build/github/azure-pipelines/stages/jobs/react-natvie-andriod-e2e-test-job.yml @@ -12,10 +12,14 @@ parameters: displayName: 'NPM packages publish configuration' type: string default: 'dev' - +- name: is1ES + type: boolean + default: false jobs: - job: ReactNative_CI_Android - pool: 'onnxruntime-Ubuntu2204-AMD-CPU' + pool: + name: onnxruntime-Ubuntu2204-AMD-CPU + os: linux variables: runCodesignValidationInjection: false ANDROID_AVD_HOME: $(Agent.TempDirectory) @@ -40,9 +44,8 @@ jobs: versionSpec: '20.x' - script: | - sudo apt install coreutils ninja-build nodejs npm yarn - npm install --global yarn - displayName: Install coreutils, ninja, npm, and yarn + sudo apt install ninja-build + displayName: Install ninja - task: DownloadPipelineArtifact@2 inputs: @@ -58,44 +61,7 @@ jobs: targetFolder: $(Build.SourcesDirectory)/js/react_native/android/libs displayName: Copy Android package to React Native directory - - script: | - npm ci - workingDirectory: '$(Build.SourcesDirectory)/js' - displayName: npm ci js - - - script: | - npm ci - workingDirectory: '$(Build.SourcesDirectory)/js/common' - displayName: npm ci js/common - - - script: | - yarn - workingDirectory: '$(Build.SourcesDirectory)/js/react_native' - displayName: yarn js/react_native - - - task: PowerShell@2 - inputs: - filePath: '$(Build.SourcesDirectory)/tools/ci_build/github/js/pack-npm-packages.ps1' - arguments: '"-dev.$(Get-Date -Format yyyyMMdd)-$(git rev-parse --short HEAD)" $(Build.SourcesDirectory) react_native' - workingDirectory: '$(Build.SourcesDirectory)' - errorActionPreference: stop - env: - ORT_JS_PACK_MODE: e2e - displayName: Pack NPM packages - - - script: | - mv $(Build.SourcesDirectory)/js/common/onnxruntime-common*.tgz onnxruntime-common.tgz - yarn add --no-lockfile file:./onnxruntime-common.tgz - mv $(Build.SourcesDirectory)/js/react_native/onnxruntime-react-native*.tgz onnxruntime-react-native.tgz - yarn add --no-lockfile file:./onnxruntime-react-native.tgz - yarn - workingDirectory: '$(Build.SourcesDirectory)/js/react_native/e2e' - displayName: Bootstrap Android and iOS e2e tests - - - script: | - yarn add --dev jest-junit - workingDirectory: '$(Build.SourcesDirectory)/js/react_native/e2e' - displayName: install jest junit reporter js/react_native/e2e + - template: steps/react-native-bootstrap-steps.yml - script: | keytool -genkey -v -keystore debug.keystore -alias androiddebugkey -storepass android \ @@ -110,15 +76,6 @@ jobs: targetFolder: $(Build.SourcesDirectory)/js/react_native/e2e/android/app/libs displayName: Copy Android package to Android e2e test directory - - script: | - yarn global add detox-cli - echo "Path: $PATH" - echo "##vso[task.prependpath]$(yarn global bin)" - echo "Updated PATH: $PATH" - echo "Detox bin directory: $(yarn global bin)" - ls $(yarn global bin) - displayName: Install detox cli tools and prepend to PATH - - script: | detox build --configuration android.emu.release workingDirectory: '$(Build.SourcesDirectory)/js/react_native/e2e' @@ -196,17 +153,30 @@ jobs: targetFolder: $(Build.ArtifactStagingDirectory) displayName: Create Artifacts onnxruntime-react-native - - task: PublishPipelineArtifact@1 - inputs: - artifact: android_e2e_test_logs_$(Build.BuildId)_$(Build.BuildNumber)_$(System.JobAttempt) - targetPath: '$(Build.SourcesDirectory)/js/react_native/e2e/artifacts' - condition: succeededOrFailed() - displayName: Publish React Native Detox E2E test logs - - - task: PublishPipelineArtifact@0 - inputs: - artifactName: '${{parameters.PackageName}}' - targetPath: '$(Build.ArtifactStagingDirectory)' - displayName: Publish Pipeline Artifact + - ${{ if eq(parameters.is1ES, true) }}: + - task: 1ES.PublishPipelineArtifact@1 + inputs: + artifact: android_e2e_test_logs_$(Build.BuildId)_$(Build.BuildNumber)_$(System.JobAttempt) + targetPath: '$(Build.SourcesDirectory)/js/react_native/e2e/artifacts' + condition: succeededOrFailed() + displayName: Publish React Native Detox E2E test logs + - task: 1ES.PublishPipelineArtifact@1 + inputs: + artifactName: '${{parameters.PackageName}}' + targetPath: '$(Build.ArtifactStagingDirectory)' + displayName: Publish Pipeline Artifact + + - ${{ if eq(parameters.is1ES, false) }}: + - task: PublishPipelineArtifact@1 + inputs: + artifact: android_e2e_test_logs_$(Build.BuildId)_$(Build.BuildNumber)_$(System.JobAttempt) + targetPath: '$(Build.SourcesDirectory)/js/react_native/e2e/artifacts' + condition: succeededOrFailed() + displayName: Publish React Native Detox E2E test logs + - task: PublishPipelineArtifact@1 + inputs: + artifactName: '${{parameters.PackageName}}' + targetPath: '$(Build.ArtifactStagingDirectory)' + displayName: Publish Pipeline Artifact - template: ../../templates/explicitly-defined-final-tasks.yml \ No newline at end of file diff --git a/tools/ci_build/github/azure-pipelines/stages/jobs/steps/react-native-bootstrap-steps.yml b/tools/ci_build/github/azure-pipelines/stages/jobs/steps/react-native-bootstrap-steps.yml new file mode 100644 index 0000000000000..d0deb57cbf303 --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/stages/jobs/steps/react-native-bootstrap-steps.yml @@ -0,0 +1,25 @@ +steps: +- script: + npm install -g detox-cli + displayName: Install detox cli tools + +- script: | + npm ci + workingDirectory: '$(Build.SourcesDirectory)/js' + displayName: npm ci js + +- script: | + npm ci + workingDirectory: '$(Build.SourcesDirectory)/js/common' + displayName: npm ci js/common + +- script: | + npm ci + npm run bootstrap-no-pods + workingDirectory: '$(Build.SourcesDirectory)/js/react_native' + displayName: bootstrap react_native + +- script: | + npm install --save-dev jest-junit + workingDirectory: '$(Build.SourcesDirectory)/js/react_native/e2e' + displayName: install jest junit reporter js/react_native/e2e \ No newline at end of file diff --git a/tools/ci_build/github/azure-pipelines/stages/nodejs-linux-packaging-stage.yml b/tools/ci_build/github/azure-pipelines/stages/nodejs-linux-packaging-stage.yml new file mode 100644 index 0000000000000..e1247565d8f5b --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/stages/nodejs-linux-packaging-stage.yml @@ -0,0 +1,57 @@ +parameters: +- name: CudaVersion + type: string + default: '12.2' + +stages: +- stage: Linux_Nodejs_Packaging_x64 + dependsOn: [] + jobs: + - job: Linux_Nodejs_Packaging_x64 + dependsOn: [] + workspace: + clean: all + timeoutInMinutes: 180 + pool: + name: 'onnxruntime-Ubuntu2204-AMD-CPU' + os: linux + variables: + - template: ../templates/common-variables.yml + - name: CUDA_VERSION_MAJOR + ${{ if eq(parameters.CudaVersion, '11.8') }}: + value: '11' + ${{ if eq(parameters.CudaVersion, '12.2') }}: + value: '12' + - name: CUDA_VERSION + value: ${{ parameters.CudaVersion }} + - name: linux_trt_version + ${{ if eq(parameters.CudaVersion, '11.8') }}: + value: ${{ variables.linux_trt_version_cuda11 }} + ${{ if eq(parameters.CudaVersion, '12.2') }}: + value: ${{ variables.linux_trt_version_cuda12 }} + steps: + - checkout: self + clean: true + submodules: recursive + - template: ../templates/get-docker-image-steps.yml + parameters: + Dockerfile: tools/ci_build/github/linux/docker/inference/x86_64/default/cuda${{ variables.CUDA_VERSION_MAJOR }}/Dockerfile + Context: tools/ci_build/github/linux/docker/inference/x86_64/default/cuda${{ variables.CUDA_VERSION_MAJOR }} + DockerBuildArgs: " + --build-arg TRT_VERSION=${{ variables.linux_trt_version }} + --build-arg BUILD_UID=$( id -u ) + " + Repository: onnxruntimecuda${{ variables.CUDA_VERSION_MAJOR }}xtrt86build + - template: ../templates/set-version-number-variables-step.yml + + - script: $(Build.SourcesDirectory)/tools/ci_build/github/linux/build_nodejs_package.sh + workingDirectory: $(Build.SourcesDirectory) + displayName: 'Build Node.js binding Package' + + - template: ../templates/nodejs-artifacts-package-and-publish-steps-posix.yml + parameters: + arch: 'x64' + os: 'linux' + artifactName: 'drop-onnxruntime-nodejs-linux-x64' + + - template: ../templates/clean-agent-build-directory-step.yml diff --git a/tools/ci_build/github/azure-pipelines/stages/nodejs-win-packaging-stage.yml b/tools/ci_build/github/azure-pipelines/stages/nodejs-win-packaging-stage.yml new file mode 100644 index 0000000000000..73e650eb07992 --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/stages/nodejs-win-packaging-stage.yml @@ -0,0 +1,192 @@ +parameters: + BuildCommand: '' + StageName: 'Windows_Nodejs_Packaging' + ArtifactName: 'drop-onnxruntime-nodejs-win' + DoEsrp: 'false' + BuildArch: 'x64' # Optional. Options: x86, x64 + sln_platform: 'x64' # Options: Win32, x64, arm, arm64 + AgentDemands: [] + BuildConfigurations: ['RelWithDebInfo'] # Options: Debug, RelWithDebInfo + EnableLto: true + # Controls whether unreleased onnx opsets are allowed. Default is set to 1 + AllowReleasedOpsetOnly: '0' + IsReleaseBuild: false + PublishWebGpuBuildTools: false + WebGpuBuildToolsArtifactName: 'Windows_WebGPU_BuildTools_x64' + DependsOnStageName: '' + +stages: +- stage: ${{ parameters.StageName }} + dependsOn: + - Setup + - ${{ if ne(parameters.DependsOnStageName, '') }}: + - ${{ parameters.DependsOnStageName }} + + jobs: + - job: ${{ parameters.StageName }} + timeoutInMinutes: 200 + strategy: + maxParallel: 2 + matrix: + ${{ each BuildConfiguration in parameters.BuildConfigurations }}: + ${{ BuildConfiguration }}: + BuildConfig: ${{ BuildConfiguration }} + workspace: + clean: all + pool: + name: onnxruntime-Win-CPU-2022 + demands: ${{ parameters.AgentDemands }} + variables: + buildDirectory: '$(Build.BinariesDirectory)' + OnnxRuntimeBuildDirectory: '$(Build.BinariesDirectory)' + runCodesignValidationInjection: ${{ parameters. DoEsrp}} #For the others, code sign is in a separated job + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + ALLOW_RELEASED_ONNX_OPSET_ONLY: ${{ parameters.AllowReleasedOpsetOnly }} + BuildDate : $[stageDependencies.Setup.Set_Variables.outputs['Set_Build_Date.BuildDate']] + BuildTime : $[stageDependencies.Setup.Set_Variables.outputs['Set_Build_Time.BuildTime']] + BuildCommandExtra: '' + ${{ if eq(parameters.EnableLto, true) }}: + build_py_lto_flag: --enable_lto + + steps: + - checkout: self + clean: true + submodules: none + + - powershell: | + if($env:TELEMETRYGUID) + { + $length = $env:TELEMETRYGUID.length + $fileContent = "#define TraceLoggingOptionMicrosoftTelemetry() \ + TraceLoggingOptionGroup("+$env:TELEMETRYGUID.substring(1, $length-2)+")" + New-Item -Path "$(Build.SourcesDirectory)\include\onnxruntime\core\platform\windows\TraceLoggingConfigPrivate.h" -ItemType "file" -Value "$fileContent" -Force + Write-Output "Enabling TELEMETRY" + } + displayName: 'Create TraceLoggingConfigPrivate.h For WinML Telemetry' + env: + TELEMETRYGUID: $(TELEMETRYGUID) + + - task: NodeTool@0 + inputs: + versionSpec: '20.x' + + - task: UsePythonVersion@0 + inputs: + versionSpec: '3.12' + addToPath: true + architecture: ${{ parameters.BuildArch }} + + # need to set PROCESSOR_ARCHITECTURE so the x86 SDK is installed correctly + - task: UseDotNet@2 + inputs: + version: 8.x + env: + PROCESSOR_ARCHITECTURE: ${{ parameters.BuildArch }} + + - task: BatchScript@1 + displayName: 'Setup VS2022 env vars' + inputs: + filename: 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat' + arguments: ${{ parameters.BuildArch }} + modifyEnvironment: true + + - ${{ if and(ne(parameters.WebGpuBuildToolsArtifactName, ''), eq(parameters.sln_platform, 'arm64')) }}: + - task: DownloadPipelineArtifact@2 + displayName: 'Download WebGPU build tools from x64 build' + inputs: + artifactName: '${{ parameters.WebGpuBuildToolsArtifactName }}' + targetPath: '$(Build.BinariesDirectory)\${{ parameters.WebGpuBuildToolsArtifactName }}' + - script: | + @echo ##vso[task.setvariable variable=LLVM_TABLEGEN_PATH]$(Build.BinariesDirectory)\${{ parameters.WebGpuBuildToolsArtifactName }}\llvm-tblgen.exe + @echo ##vso[task.setvariable variable=CLANG_TABLEGEN_PATH]$(Build.BinariesDirectory)\${{ parameters.WebGpuBuildToolsArtifactName }}\clang-tblgen.exe + displayName: 'Set tablegen paths' + - powershell: | + Write-Host "Using LLVM_TABLEGEN_PATH: $(LLVM_TABLEGEN_PATH)" + Write-Host "Using CLANG_TABLEGEN_PATH: $(CLANG_TABLEGEN_PATH)" + Write-Host "##vso[task.setvariable variable=BuildCommandExtra]--cmake_extra_defines LLVM_TABLEGEN=$(LLVM_TABLEGEN_PATH) CLANG_TABLEGEN=$(CLANG_TABLEGEN_PATH)" + displayName: 'Set build flags for WebGPU cross-compilation' + + - powershell: | + python tools\ci_build\build.py --build_dir $(Build.BinariesDirectory) ${{ parameters.BuildCommand }} $(BuildCommandExtra) --use_binskim_compliant_compile_flags --parallel --build --update --config $(BuildConfig) --msbuild_extra_options IncludeMobileTargets=false ${{ variables.build_py_lto_flag }} + + - ${{ if notIn(parameters['sln_platform'], 'Win32', 'x64') }}: + # Use cross-compiled protoc + - script: | + @echo ##vso[task.setvariable variable=ProtocDirectory]$(Build.BinariesDirectory)\installed\bin + + # The Configuration variable is required to build C# + - script: | + @echo ##vso[task.setvariable variable=Configuration]$(BuildConfig) + displayName: 'Set Configuration variable' + + # Node.js Publish + - task: BatchScript@1 + displayName: 'Setup VS env vars' + inputs: + filename: 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat' + arguments: ${{ parameters.BuildArch }} + modifyEnvironment: true + - task: CopyFiles@2 + displayName: 'Copy DirectML binaries to: $(Build.SourcesDirectory)\js\node\bin\napi-v3\win32\${{ parameters.sln_platform }}' + inputs: + SourceFolder: '$(Build.BinariesDirectory)\$(BuildConfig)\$(BuildConfig)' + Contents: 'DirectML.dll' + TargetFolder: '$(Build.SourcesDirectory)\js\node\bin\napi-v3\win32\${{ parameters.sln_platform }}' + - powershell: | + $dxcZipUrl = "https://github.com/microsoft/DirectXShaderCompiler/releases/download/v1.8.2502/dxc_2025_02_20.zip" + $dxcZipPath = "$(Build.BinariesDirectory)\dxc.zip" + $dxcExtractPath = "$(Build.BinariesDirectory)\dxc_extracted" + $targetArch = "${{ parameters.sln_platform }}" + + # Download the DXC package + Write-Host "Downloading DXC release from $dxcZipUrl" + Invoke-WebRequest -Uri $dxcZipUrl -OutFile $dxcZipPath + + # Create extraction directory + if (-not (Test-Path $dxcExtractPath)) { + New-Item -Path $dxcExtractPath -ItemType Directory -Force + } + + # Extract the zip file + Write-Host "Extracting DXC package to $dxcExtractPath" + Expand-Archive -Path $dxcZipPath -DestinationPath $dxcExtractPath -Force + + # Copy the necessary DLLs to the target directory + $sourcePath = Join-Path $dxcExtractPath "bin\$targetArch" + $targetPath = "$(Build.SourcesDirectory)\js\node\bin\napi-v3\win32\$targetArch" + + Write-Host "Copying dxil.dll and dxcompiler.dll from $sourcePath to $targetPath" + Copy-Item -Path "$sourcePath\dxil.dll" -Destination $targetPath -Force + Copy-Item -Path "$sourcePath\dxcompiler.dll" -Destination $targetPath -Force + + Write-Host "DXC DLLs successfully copied to the target directory" + displayName: 'Download and Copy DXC Binaries' + - template: ../templates/win-esrp-dll.yml + parameters: + FolderPath: '$(Build.SourcesDirectory)\js\node\bin\napi-v3\win32\${{ parameters.sln_platform }}' + DisplayName: 'ESRP - Sign Node.js binding binaries' + DoEsrp: ${{ parameters.DoEsrp }} + Pattern: '*.dll,*.node' + + - script: | + del /Q $(Build.SourcesDirectory)\js\node\bin\napi-v3\win32\${{ parameters.sln_platform }}\CodeSignSummary-*.* + call npm pack + copy $(Build.SourcesDirectory)\js\node\onnxruntime-*.tgz $(Build.ArtifactStagingDirectory) + workingDirectory: '$(Build.SourcesDirectory)\js\node' + displayName: 'Create NPM Package' + + - task: 1ES.PublishPipelineArtifact@1 + inputs: + targetPath: '$(Build.SourcesDirectory)\js\node\bin\napi-v3\win32\${{ parameters.sln_platform }}' + artifactName: ${{ parameters.ArtifactName }} + + - ${{ if and(eq(parameters.PublishWebGpuBuildTools, true), eq(parameters.sln_platform, 'x64')) }}: + - script: | + mkdir $(Build.ArtifactStagingDirectory)\${{ parameters.WebGpuBuildToolsArtifactName }} + copy $(Build.BinariesDirectory)\$(BuildConfig)\_deps\dawn-build\third_party\dxc\RelWithDebInfo\bin\llvm-tblgen.exe $(Build.ArtifactStagingDirectory)\${{ parameters.WebGpuBuildToolsArtifactName }} + copy $(Build.BinariesDirectory)\$(BuildConfig)\_deps\dawn-build\third_party\dxc\RelWithDebInfo\bin\clang-tblgen.exe $(Build.ArtifactStagingDirectory)\${{ parameters.WebGpuBuildToolsArtifactName }} + displayName: 'Copy WebGPU build tools' + - task: 1ES.PublishPipelineArtifact@1 + inputs: + targetPath: '$(Build.ArtifactStagingDirectory)\${{ parameters.WebGpuBuildToolsArtifactName }}' + artifactName: ${{ parameters.WebGpuBuildToolsArtifactName }} diff --git a/tools/ci_build/github/azure-pipelines/stages/nuget-combine-cuda-stage.yml b/tools/ci_build/github/azure-pipelines/stages/nuget-combine-cuda-stage.yml index 9c7fbc24ab1b6..a4fe78a7088e3 100644 --- a/tools/ci_build/github/azure-pipelines/stages/nuget-combine-cuda-stage.yml +++ b/tools/ci_build/github/azure-pipelines/stages/nuget-combine-cuda-stage.yml @@ -1,7 +1,4 @@ parameters: -- name: DoCompliance - type: boolean - - name: DoEsrp type: boolean @@ -42,6 +39,11 @@ stages: buildJava: ${{ parameters.buildJava }} buildNodejs: ${{ parameters.buildNodejs }} +- ${{ if eq(parameters.buildNodejs, 'true') }}: + - template: nodejs-linux-packaging-stage.yml + parameters: + CudaVersion: ${{ parameters.CudaVersion }} + - template: nuget-win-cuda-packaging-stage.yml parameters: RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} @@ -53,7 +55,6 @@ stages: - template: nuget-cuda-packaging-stage.yml parameters: - DoCompliance: ${{ parameters.DoCompliance }} DoEsrp: ${{ parameters.DoEsrp }} IsReleaseBuild: ${{ parameters.IsReleaseBuild }} SpecificArtifact: ${{ parameters.SpecificArtifact }} @@ -61,8 +62,8 @@ stages: - template: ../nuget/templates/test_win.yml parameters: - AgentPool : 'onnxruntime-Win2022-GPU-A10' - NugetPackageName : 'Microsoft.ML.OnnxRuntime.Gpu' + AgentPool: 'onnxruntime-Win2022-GPU-A10' + NugetPackageName: 'Microsoft.ML.OnnxRuntime.Gpu' ArtifactSuffix: 'GPU' StageSuffix: 'GPU' Skipx86Tests: 'true' @@ -72,8 +73,8 @@ stages: - template: ../nuget/templates/test_win.yml parameters: - AgentPool : 'onnxruntime-Win2022-GPU-A10' - NugetPackageName : 'Microsoft.ML.OnnxRuntime.Gpu.Windows' + AgentPool: 'onnxruntime-Win2022-GPU-A10' + NugetPackageName: 'Microsoft.ML.OnnxRuntime.Gpu.Windows' ArtifactSuffix: 'GPU' StageSuffix: 'GPU' MoreSuffix: '_Windows' @@ -84,21 +85,21 @@ stages: - template: ../nuget/templates/test_linux.yml parameters: - AgentPool : Onnxruntime-Linux-GPU-A10 + AgentPool: Onnxruntime-Linux-GPU-A10 ArtifactSuffix: 'GPU' StageSuffix: 'GPU' - NugetPackageName : 'Microsoft.ML.OnnxRuntime.Gpu' + NugetPackageName: 'Microsoft.ML.OnnxRuntime.Gpu' CudaVersion: ${{ parameters.CudaVersion }} SpecificArtifact: ${{ parameters.specificArtifact }} BuildId: ${{ parameters.BuildId }} - template: ../nuget/templates/test_linux.yml parameters: - AgentPool : Onnxruntime-Linux-GPU-A10 + AgentPool: Onnxruntime-Linux-GPU-A10 ArtifactSuffix: 'GPU' StageSuffix: 'GPU' MoreSuffix: '_Linux' - NugetPackageName : 'Microsoft.ML.OnnxRuntime.Gpu.Linux' + NugetPackageName: 'Microsoft.ML.OnnxRuntime.Gpu.Linux' CudaVersion: ${{ parameters.CudaVersion }} SpecificArtifact: ${{ parameters.specificArtifact }} BuildId: ${{ parameters.BuildId }} diff --git a/tools/ci_build/github/azure-pipelines/stages/nuget-cuda-packaging-stage.yml b/tools/ci_build/github/azure-pipelines/stages/nuget-cuda-packaging-stage.yml index 8fabb80a73869..84b6d30ee32ac 100644 --- a/tools/ci_build/github/azure-pipelines/stages/nuget-cuda-packaging-stage.yml +++ b/tools/ci_build/github/azure-pipelines/stages/nuget-cuda-packaging-stage.yml @@ -1,7 +1,4 @@ parameters: -- name: DoCompliance - type: boolean - - name: DoEsrp type: boolean @@ -21,206 +18,194 @@ stages: # Win/Linux CUDA Combined packaging - stage: NuGet_Packaging_GPU dependsOn: - - Setup - - Windows_Packaging_CUDA - - Windows_Packaging_TensorRT - - Linux_C_API_Packaging_GPU -# This is need for Download Linux CustomOp TestData - - Linux_C_API_Packaging_CPU + - Setup + - Windows_Packaging_CUDA + - Windows_Packaging_TensorRT + - Linux_C_API_Packaging_GPU + # This is need for Download Linux CustomOp TestData + - Linux_C_API_Packaging_CPU condition: succeeded() jobs: - - job: NuGet_Packaging_GPU - workspace: - clean: all - pool: 'Onnxruntime-Win-CPU-2022' - variables: - breakCodesignValidationInjection: ${{ parameters.DoEsrp }} - ReleaseVersionSuffix: $[stageDependencies.Setup.Set_Variables.outputs['Set_Release_Version_Suffix.ReleaseVersionSuffix']] - BuildDate: $[format('{0:yyyyMMdd}', pipeline.startTime)] - BuildTime: $[format('{0:HHmm}', pipeline.startTime)] - - steps: - - checkout: self - submodules: true - - template: ../templates/flex-downloadPipelineArtifact.yml - parameters: - StepName: 'Download Pipeline Artifact - NuGet' - ArtifactName: 'onnxruntime-win-x64-cuda' - TargetPath: '$(Build.BinariesDirectory)/nuget-artifact' - SpecificArtifact: ${{ parameters.SpecificArtifact }} - BuildId: ${{ parameters.BuildId }} - - - template: ../templates/flex-downloadPipelineArtifact.yml - parameters: - StepName: 'Download Pipeline Artifact - NuGet' - ArtifactName: 'onnxruntime-win-x64-tensorrt' - TargetPath: '$(Build.BinariesDirectory)/nuget-artifact' - SpecificArtifact: ${{ parameters.SpecificArtifact }} - BuildId: ${{ parameters.BuildId }} - - - template: ../templates/flex-downloadPipelineArtifact.yml - parameters: - StepName: 'Download Pipeline Artifact - NuGet' - ArtifactName: 'onnxruntime-linux-x64-cuda' - TargetPath: '$(Build.BinariesDirectory)/nuget-artifact' - SpecificArtifact: ${{ parameters.SpecificArtifact }} - BuildId: ${{ parameters.BuildId }} - - - template: ../templates/flex-downloadPipelineArtifact.yml - parameters: - StepName: 'Download Pipeline Artifact - NuGet' - ArtifactName: 'onnxruntime-linux-x64-tensorrt' - TargetPath: '$(Build.BinariesDirectory)/nuget-artifact' - SpecificArtifact: ${{ parameters.SpecificArtifact }} - BuildId: ${{ parameters.BuildId }} - - # Reconstruct the build dir - - task: PowerShell@2 - displayName: 'PS: Extract nuget files gpu' - inputs: - targetType: filePath - filePath: $(Build.SourcesDirectory)\tools\ci_build\github\windows\extract_nuget_files_gpu.ps1 - - - script: | - dir - workingDirectory: '$(Build.BinariesDirectory)/nuget-artifact' - displayName: 'List artifacts' - - - script: | - mklink /D /J models C:\local\models - workingDirectory: '$(Build.BinariesDirectory)' - displayName: 'Create models link' - - - task: NuGetToolInstaller@0 - displayName: Use Nuget 6.10.x - inputs: - versionSpec: 6.10.x - - - task: PowerShell@2 - displayName: Install MAUI workloads - inputs: - targetType: 'inline' - script: | - dotnet workload install android ios maccatalyst - workingDirectory: '$(Build.SourcesDirectory)\csharp' - - - task: MSBuild@1 - displayName: 'Restore NuGet Packages and create project.assets.json' - inputs: - solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.sln' - platform: 'Any CPU' - configuration: RelWithDebInfo - msbuildArguments: '-t:restore -p:OrtPackageId="Microsoft.ML.OnnxRuntime.Gpu"' - workingDirectory: '$(Build.SourcesDirectory)\csharp' - - - task: MSBuild@1 - displayName: 'Build C# bindings' - inputs: - solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.sln' - configuration: RelWithDebInfo - platform: 'Any CPU' - msbuildArguments: > - -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" - -p:OrtPackageId="Microsoft.ML.OnnxRuntime.Gpu" - -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} - -p:ReleaseVersionSuffix=$(ReleaseVersionSuffix) - workingDirectory: '$(Build.SourcesDirectory)\csharp' - - - template: ../templates/win-esrp-dll.yml - parameters: - FolderPath: '$(Build.SourcesDirectory)\csharp\src\Microsoft.ML.OnnxRuntime\bin\RelWithDebInfo' - DisplayName: 'ESRP - Sign C# dlls' - DoEsrp: ${{ parameters.DoEsrp }} - - - task: UsePythonVersion@0 - displayName: 'Use Python' - inputs: - versionSpec: 3.12 - - - task: MSBuild@1 - displayName: 'Build Nuget Packages' - inputs: - solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.proj' - configuration: RelWithDebInfo - platform: 'Any CPU' - msbuildArguments: '-t:CreatePackage -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId=Microsoft.ML.OnnxRuntime.Gpu -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} + - job: NuGet_Packaging_GPU + workspace: + clean: all + pool: + name: 'onnxruntime-Win-CPU-2022' + variables: + breakCodesignValidationInjection: ${{ parameters.DoEsrp }} + ReleaseVersionSuffix: $[stageDependencies.Setup.Set_Variables.outputs['Set_Release_Version_Suffix.ReleaseVersionSuffix']] + BuildDate: $[format('{0:yyyyMMdd}', pipeline.startTime)] + BuildTime: $[format('{0:HHmm}', pipeline.startTime)] + + steps: + - checkout: self + submodules: true + - template: ../templates/flex-downloadPipelineArtifact.yml + parameters: + StepName: 'Download Pipeline Artifact - NuGet' + ArtifactName: 'onnxruntime-win-x64-cuda' + TargetPath: '$(Build.BinariesDirectory)/nuget-artifact' + SpecificArtifact: ${{ parameters.SpecificArtifact }} + BuildId: ${{ parameters.BuildId }} + + - template: ../templates/flex-downloadPipelineArtifact.yml + parameters: + StepName: 'Download Pipeline Artifact - NuGet' + ArtifactName: 'onnxruntime-win-x64-tensorrt' + TargetPath: '$(Build.BinariesDirectory)/nuget-artifact' + SpecificArtifact: ${{ parameters.SpecificArtifact }} + BuildId: ${{ parameters.BuildId }} + + - template: ../templates/flex-downloadPipelineArtifact.yml + parameters: + StepName: 'Download Pipeline Artifact - NuGet' + ArtifactName: 'onnxruntime-linux-x64-cuda' + TargetPath: '$(Build.BinariesDirectory)/nuget-artifact' + SpecificArtifact: ${{ parameters.SpecificArtifact }} + BuildId: ${{ parameters.BuildId }} + + - template: ../templates/flex-downloadPipelineArtifact.yml + parameters: + StepName: 'Download Pipeline Artifact - NuGet' + ArtifactName: 'onnxruntime-linux-x64-tensorrt' + TargetPath: '$(Build.BinariesDirectory)/nuget-artifact' + SpecificArtifact: ${{ parameters.SpecificArtifact }} + BuildId: ${{ parameters.BuildId }} + + # Reconstruct the build dir + - task: PowerShell@2 + displayName: 'PS: Extract nuget files gpu' + inputs: + targetType: filePath + filePath: $(Build.SourcesDirectory)\tools\ci_build\github\windows\extract_nuget_files_gpu.ps1 + + - script: | + dir + workingDirectory: '$(Build.BinariesDirectory)/nuget-artifact' + displayName: 'List artifacts' + + - script: | + mklink /D /J models C:\local\models + workingDirectory: '$(Build.BinariesDirectory)' + displayName: 'Create models link' + + - task: NuGetToolInstaller@0 + displayName: Use Nuget 6.10.x + inputs: + versionSpec: 6.10.x + + - task: MSBuild@1 + displayName: 'Restore NuGet Packages and create project.assets.json' + inputs: + solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.DesktopOnly.CSharp.sln' + platform: 'Any CPU' + configuration: RelWithDebInfo + msbuildArguments: '-t:restore -p:OrtPackageId="Microsoft.ML.OnnxRuntime.Gpu"' + workingDirectory: '$(Build.SourcesDirectory)\csharp' + + - task: MSBuild@1 + displayName: 'Build C# bindings' + inputs: + solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.DesktopOnly.CSharp.sln' + configuration: RelWithDebInfo + platform: 'Any CPU' + msbuildArguments: > + -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" + -p:OrtPackageId="Microsoft.ML.OnnxRuntime.Gpu" + -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} + -p:ReleaseVersionSuffix=$(ReleaseVersionSuffix) + workingDirectory: '$(Build.SourcesDirectory)\csharp' + + - template: ../templates/win-esrp-dll.yml + parameters: + FolderPath: '$(Build.SourcesDirectory)\csharp\src\Microsoft.ML.OnnxRuntime\bin\RelWithDebInfo' + DisplayName: 'ESRP - Sign C# dlls' + DoEsrp: ${{ parameters.DoEsrp }} + + - task: UsePythonVersion@0 + displayName: 'Use Python' + inputs: + versionSpec: 3.12 + + - task: MSBuild@1 + displayName: 'Build Nuget Packages' + inputs: + solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.proj' + configuration: RelWithDebInfo + platform: 'Any CPU' + msbuildArguments: '-t:CreatePackage -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId=Microsoft.ML.OnnxRuntime.Gpu -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} -p:ReleaseVersionSuffix=$(ReleaseVersionSuffix) -p:CurrentDate=$(BuildDate) -p:CurrentTime=$(BuildTime)' - workingDirectory: '$(Build.SourcesDirectory)\csharp' - - - task: BatchScript@1 - displayName: 'Add TensorRT header file to the native nuGet package' - inputs: - filename: $(Build.SourcesDirectory)\tools\ci_build\github\windows\bundle_nuget_with_native_headers.bat - workingFolder: $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo - - - task: CopyFiles@2 - displayName: 'Copy nuget packages to: $(Build.ArtifactStagingDirectory)' - inputs: - SourceFolder: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo' - Contents: '*.snupkg' - TargetFolder: '$(Build.ArtifactStagingDirectory)' - - - task: CopyFiles@2 - displayName: 'Copy nuget packages to: $(Build.ArtifactStagingDirectory)' - inputs: - SourceFolder: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo' - Contents: '*.nupkg' - TargetFolder: '$(Build.ArtifactStagingDirectory)' - - - task: CopyFiles@2 - displayName: 'Copy nuget packages to: $(Build.ArtifactStagingDirectory)' - inputs: - SourceFolder: '$(Build.SourcesDirectory)\csharp\src\Microsoft.ML.OnnxRuntime\bin\RelWithDebInfo' - Contents: '*.nupkg' - TargetFolder: '$(Build.ArtifactStagingDirectory)' - - - template: ../templates/esrp_nuget.yml - parameters: - DisplayName: 'ESRP - sign NuGet package' - FolderPath: '$(Build.ArtifactStagingDirectory)' - DoEsrp: ${{ parameters.DoEsrp }} - - - template: ../templates/validate-package.yml - parameters: - PackageType: 'nuget' - PackagePath: '$(Build.ArtifactStagingDirectory)' - PlatformsSupported: 'win-x64,linux-x64' - # 1* stands for version number. we use it to filter Gpu.Windows and Gpu.Linux packages - PackageName: 'Microsoft.ML.OnnxRuntime.Gpu.1*nupkg' - VerifyNugetSigning: false - - - template: ../templates/validate-package.yml - parameters: - PackageType: 'nuget' - PackagePath: '$(Build.ArtifactStagingDirectory)' - PackageName: 'Microsoft.ML.OnnxRuntime.Gpu.Windows.*nupkg' - PlatformsSupported: 'win-x64' - VerifyNugetSigning: false - - - template: ../templates/validate-package.yml - parameters: - PackageType: 'nuget' - PackagePath: '$(Build.ArtifactStagingDirectory)' - PackageName: 'Microsoft.ML.OnnxRuntime.Gpu.Linux.*nupkg' - PlatformsSupported: 'linux-x64' - VerifyNugetSigning: false - - - task: MSBuild@1 - displayName: 'Clean C#' - inputs: - solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.sln' - platform: 'Any CPU' - configuration: RelWithDebInfo - msbuildArguments: '-t:Clean -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId=Microsoft.ML.OnnxRuntime.Gpu' - workingDirectory: '$(Build.SourcesDirectory)\csharp' - - - template: ../templates/component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' - - - task: PublishPipelineArtifact@0 - displayName: 'Publish Pipeline NuGet Artifact' - inputs: - artifactName: 'drop-signed-nuget-GPU' - targetPath: '$(Build.ArtifactStagingDirectory)' - + workingDirectory: '$(Build.SourcesDirectory)\csharp' + + - task: BatchScript@1 + displayName: 'Add TensorRT header file to the native nuGet package' + inputs: + filename: $(Build.SourcesDirectory)\tools\ci_build\github\windows\bundle_nuget_with_native_headers.bat + workingFolder: $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo + + - task: CopyFiles@2 + displayName: 'Copy nuget packages to: $(Build.ArtifactStagingDirectory)' + inputs: + SourceFolder: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo' + Contents: '*.snupkg' + TargetFolder: '$(Build.ArtifactStagingDirectory)' + + - task: CopyFiles@2 + displayName: 'Copy nuget packages to: $(Build.ArtifactStagingDirectory)' + inputs: + SourceFolder: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo' + Contents: '*.nupkg' + TargetFolder: '$(Build.ArtifactStagingDirectory)' + + - task: CopyFiles@2 + displayName: 'Copy nuget packages to: $(Build.ArtifactStagingDirectory)' + inputs: + SourceFolder: '$(Build.SourcesDirectory)\csharp\src\Microsoft.ML.OnnxRuntime\bin\RelWithDebInfo' + Contents: '*.nupkg' + TargetFolder: '$(Build.ArtifactStagingDirectory)' + + - template: ../templates/esrp_nuget.yml + parameters: + DisplayName: 'ESRP - sign NuGet package' + FolderPath: '$(Build.ArtifactStagingDirectory)' + DoEsrp: ${{ parameters.DoEsrp }} + + - template: ../templates/validate-package.yml + parameters: + PackageType: 'nuget' + PackagePath: '$(Build.ArtifactStagingDirectory)' + PlatformsSupported: 'win-x64,linux-x64' + # 1* stands for version number. we use it to filter Gpu.Windows and Gpu.Linux packages + PackageName: 'Microsoft.ML.OnnxRuntime.Gpu.1*nupkg' + VerifyNugetSigning: false + + - template: ../templates/validate-package.yml + parameters: + PackageType: 'nuget' + PackagePath: '$(Build.ArtifactStagingDirectory)' + PackageName: 'Microsoft.ML.OnnxRuntime.Gpu.Windows.*nupkg' + PlatformsSupported: 'win-x64' + VerifyNugetSigning: false + + - template: ../templates/validate-package.yml + parameters: + PackageType: 'nuget' + PackagePath: '$(Build.ArtifactStagingDirectory)' + PackageName: 'Microsoft.ML.OnnxRuntime.Gpu.Linux.*nupkg' + PlatformsSupported: 'linux-x64' + VerifyNugetSigning: false + + - task: MSBuild@1 + displayName: 'Clean C#' + inputs: + solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.DesktopOnly.CSharp.sln' + platform: 'Any CPU' + configuration: RelWithDebInfo + msbuildArguments: '-t:Clean -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId=Microsoft.ML.OnnxRuntime.Gpu' + workingDirectory: '$(Build.SourcesDirectory)\csharp' + + - task: 1ES.PublishPipelineArtifact@1 + displayName: 'Publish Pipeline NuGet Artifact' + inputs: + artifactName: 'drop-signed-nuget-GPU' + targetPath: '$(Build.ArtifactStagingDirectory)' diff --git a/tools/ci_build/github/azure-pipelines/stages/nuget-cuda-publishing-stage.yml b/tools/ci_build/github/azure-pipelines/stages/nuget-cuda-publishing-stage.yml index b802dd43f9058..f6d78707d5b9c 100644 --- a/tools/ci_build/github/azure-pipelines/stages/nuget-cuda-publishing-stage.yml +++ b/tools/ci_build/github/azure-pipelines/stages/nuget-cuda-publishing-stage.yml @@ -1,71 +1,71 @@ parameters: - - name: artifact_feed - type: string - default: 'onnxruntime-cuda-12' +- name: artifact_feed + type: string + default: 'onnxruntime-cuda-12' stages: - - stage: NuGet_Publishing_GPU - jobs: - - job: NuGet_Publishing_GPU - workspace: - clean: all - variables: - - name: GDN_CODESIGN_TARGETDIRECTORY - value: '$(Build.BinariesDirectory)/nuget-artifact/final-package' - pool: 'onnxruntime-Win-CPU-2022' - steps: - - checkout: none +- stage: NuGet_Publishing_GPU + jobs: + - job: NuGet_Publishing_GPU + workspace: + clean: all + variables: + - name: GDN_CODESIGN_TARGETDIRECTORY + value: '$(Build.BinariesDirectory)/nuget-artifact/final-package' + pool: 'onnxruntime-Win-CPU-2022' + steps: + - checkout: none - - task: NuGetToolInstaller@1 - inputs: - versionSpec: 6.8.x + - task: NuGetToolInstaller@1 + inputs: + versionSpec: 6.8.x - - script: mkdir "$(Build.BinariesDirectory)\nuget-artifact\final-package" - - - download: build - displayName: 'Download Pipeline Artifact - Signed NuGet Package' - artifact: 'drop-signed-nuget-GPU' - - - script: move "$(Pipeline.Workspace)\build\drop-signed-nuget-GPU\*" "$(Build.BinariesDirectory)\nuget-artifact\final-package" - - - powershell: | - New-Item -Path $(Agent.TempDirectory) -Name "binfiles" -ItemType "directory" - $base_path_name = Join-Path -Path $(Agent.TempDirectory) -ChildPath "binfiles" - Get-ChildItem $Env:BUILD_BINARIESDIRECTORY\nuget-artifact\final-package -Filter *.nupkg | - Foreach-Object { - $dir_name = Join-Path -Path $base_path_name -ChildPath $_.Basename - $cmd = "7z.exe x $($_.FullName) -y -o$dir_name" - Write-Output $cmd - Invoke-Expression -Command $cmd - } - dir $(Agent.TempDirectory) - tree $(Agent.TempDirectory) - workingDirectory: '$(Agent.TempDirectory)' + - script: mkdir "$(Build.BinariesDirectory)\nuget-artifact\final-package" - - task: CodeSign@1 - displayName: 'Run Codesign Validation' + - download: build + displayName: 'Download Pipeline Artifact - Signed NuGet Package' + artifact: 'drop-signed-nuget-GPU' - - task: PublishSecurityAnalysisLogs@3 - displayName: 'Publish Security Analysis Logs' - continueOnError: true + - script: move "$(Pipeline.Workspace)\build\drop-signed-nuget-GPU\*" "$(Build.BinariesDirectory)\nuget-artifact\final-package" - - task: PostAnalysis@2 - inputs: - GdnBreakAllTools: true - GdnBreakPolicy: M365 - GdnBreakPolicyMinSev: Error + - powershell: | + New-Item -Path $(Agent.TempDirectory) -Name "binfiles" -ItemType "directory" + $base_path_name = Join-Path -Path $(Agent.TempDirectory) -ChildPath "binfiles" + Get-ChildItem $Env:BUILD_BINARIESDIRECTORY\nuget-artifact\final-package -Filter *.nupkg | + Foreach-Object { + $dir_name = Join-Path -Path $base_path_name -ChildPath $_.Basename + $cmd = "7z.exe x $($_.FullName) -y -o$dir_name" + Write-Output $cmd + Invoke-Expression -Command $cmd + } + dir $(Agent.TempDirectory) + tree $(Agent.TempDirectory) + workingDirectory: '$(Agent.TempDirectory)' - - template: ../nuget/templates/get-nuget-package-version-as-variable.yml - parameters: - packageFolder: '$(Build.BinariesDirectory)/nuget-artifact/final-package' - #This task must be run on a Windows machine - - task: NuGetCommand@2 - displayName: 'NuGet push ${{ parameters.artifact_feed }}' - inputs: - command: push - packagesToPush: '$(Build.BinariesDirectory)/nuget-artifact/final-package/*.nupkg' - publishVstsFeed: 'PublicPackages/${{ parameters.artifact_feed }}' - allowPackageConflicts: true + - task: CodeSign@1 + displayName: 'Run Codesign Validation' + + - task: PublishSecurityAnalysisLogs@3 + displayName: 'Publish Security Analysis Logs' + continueOnError: true + + - task: PostAnalysis@2 + inputs: + GdnBreakAllTools: true + GdnBreakPolicy: M365 + GdnBreakPolicyMinSev: Error + + - template: ../nuget/templates/get-nuget-package-version-as-variable.yml + parameters: + packageFolder: '$(Build.BinariesDirectory)/nuget-artifact/final-package' + #This task must be run on a Windows machine + - task: 1ES.PublishNuget@1 + displayName: 'NuGet push ${{ parameters.artifact_feed }}' + inputs: + packagesToPush: '$(Build.BinariesDirectory)/nuget-artifact/final-package/*.nupkg' + packageParentPath: '$(Build.BinariesDirectory)' + publishVstsFeed: 'PublicPackages/${{ parameters.artifact_feed }}' + allowPackageConflicts: true diff --git a/tools/ci_build/github/azure-pipelines/stages/nuget-linux-cuda-packaging-stage.yml b/tools/ci_build/github/azure-pipelines/stages/nuget-linux-cuda-packaging-stage.yml index 6e9e3c80a298c..e36fe98fe0ac2 100644 --- a/tools/ci_build/github/azure-pipelines/stages/nuget-linux-cuda-packaging-stage.yml +++ b/tools/ci_build/github/azure-pipelines/stages/nuget-linux-cuda-packaging-stage.yml @@ -1,7 +1,7 @@ parameters: - name: CudaVersion type: string - default: '11.8' + default: '12.2' - name: buildJava type: boolean - name: buildNodejs @@ -15,7 +15,9 @@ stages: workspace: clean: all timeoutInMinutes: 150 - pool: 'onnxruntime-Ubuntu2204-AMD-CPU' + pool: + name: 'onnxruntime-Ubuntu2204-AMD-CPU' + os: linux variables: - name: CUDA_VERSION_MAJOR ${{ if eq(parameters.CudaVersion, '11.8') }}: @@ -30,9 +32,7 @@ stages: parameters: Dockerfile: tools/ci_build/github/linux/docker/inference/x86_64/default/cuda${{ variables.CUDA_VERSION_MAJOR }}/Dockerfile Context: tools/ci_build/github/linux/docker/inference/x86_64/default/cuda${{ variables.CUDA_VERSION_MAJOR }} - DockerBuildArgs: " - --build-arg BUILD_UID=$( id -u ) - " + DockerBuildArgs: " --build-arg BUILD_UID=$( id -u )" Repository: onnxruntimecuda${{ variables.CUDA_VERSION_MAJOR }}build - script: $(Build.SourcesDirectory)/tools/ci_build/github/linux/build_cuda_c_api_package.sh @@ -48,6 +48,7 @@ stages: version: '$(OnnxRuntimeVersion)' libraryName: 'libonnxruntime.so' nativeLibraryName: 'libonnxruntime4j_jni.so' + is1ES: true - template: ../templates/c-api-artifacts-package-and-publish-steps-posix.yml parameters: @@ -56,9 +57,6 @@ stages: artifactNameNoVersionString: 'onnxruntime-linux-x64-cuda' libraryName: 'libonnxruntime.so.$(OnnxRuntimeVersion)' - - template: ../templates/component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' - template: ../templates/clean-agent-build-directory-step.yml # Linux CUDA with TensorRT Packaging - job: Linux_C_API_Packaging_TensorRT @@ -66,7 +64,9 @@ stages: workspace: clean: all timeoutInMinutes: 180 - pool: 'onnxruntime-Ubuntu2204-AMD-CPU' + pool: + name: 'onnxruntime-Ubuntu2204-AMD-CPU' + os: linux variables: - template: ../templates/common-variables.yml - name: CUDA_VERSION_MAJOR @@ -109,13 +109,7 @@ stages: version: '$(OnnxRuntimeVersion)' libraryName: 'libonnxruntime.so' nativeLibraryName: 'libonnxruntime4j_jni.so' - - - ${{ if eq(parameters.buildNodejs, 'true') }}: - - template: ../templates/nodejs-artifacts-package-and-publish-steps-posix.yml - parameters: - arch: 'x64' - os: 'linux' - artifactName: 'drop-onnxruntime-nodejs-linux-x64-tensorrt' + is1ES: true - template: ../templates/c-api-artifacts-package-and-publish-steps-posix.yml parameters: @@ -124,10 +118,6 @@ stages: artifactNameNoVersionString: 'onnxruntime-linux-x64-tensorrt' libraryName: 'libonnxruntime.so.$(OnnxRuntimeVersion)' - - - template: ../templates/component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' - template: ../templates/clean-agent-build-directory-step.yml # Linux CUDA Combined Testing and Publishing - stage: Linux_Packaging_combined_CUDA @@ -138,7 +128,9 @@ stages: condition: succeeded() workspace: clean: all - pool: 'Onnxruntime-Linux-GPU' + pool: + name: 'Onnxruntime-Linux-GPU-A10' + os: linux variables: - template: ../templates/common-variables.yml - name: CUDA_VERSION_MAJOR @@ -218,10 +210,7 @@ stages: /src_dir/onnxruntime-inference-examples/c_cxx/squeezenet/run_capi_application.sh -o /src_dir/onnxruntime -p /artifact_src/onnxruntime-linux-x64-gpu-$(OnnxRuntimeVersion).tgz -w /src_dir/onnxruntime-inference-examples/c_cxx/squeezenet workingDirectory: '$(Build.ArtifactStagingDirectory)' - - task: PublishPipelineArtifact@1 + - task: 1ES.PublishPipelineArtifact@1 inputs: - targetPath: '$(Build.ArtifactStagingDirectory)/onnxruntime-linux-x64-gpu-$(OnnxRuntimeVersion).tgz' + targetPath: '$(Build.ArtifactStagingDirectory)' artifactName: 'onnxruntime-linux-x64-gpu' - - template: ../templates/component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' diff --git a/tools/ci_build/github/azure-pipelines/stages/nuget-qnn-packaging-stage.yml b/tools/ci_build/github/azure-pipelines/stages/nuget-qnn-packaging-stage.yml new file mode 100644 index 0000000000000..03802746cec3d --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/stages/nuget-qnn-packaging-stage.yml @@ -0,0 +1,76 @@ +parameters: +- name: DoEsrp + displayName: Run code sign tasks? Must be true if you are doing an Onnx Runtime release. + type: boolean + default: true + +stages: +- stage: NuGet_Packaging_QNN + pool: + name: 'Onnxruntime-QNNEP-Windows-2022-CPU' + dependsOn: + - OnnxRuntime_QNN_Nuget_Win_x64 + - OnnxRuntime_QNN_Nuget_Win_Arm64 + condition: succeeded() + jobs: + - job: NuGet_Packaging_QNN + workspace: + clean: all + steps: + - task: DownloadPipelineArtifact@0 + displayName: 'Download Pipeline Artifact - QNN NuGet x64' + inputs: + artifactName: 'drop-nuget-qnn-x64' + targetPath: '$(Build.BinariesDirectory)/nuget-artifact-x64' + + - task: DownloadPipelineArtifact@0 + displayName: 'Download Pipeline Artifact - QNN NuGet arm64' + inputs: + artifactName: 'drop-nuget-qnn-arm64' + targetPath: '$(Build.BinariesDirectory)/nuget-artifact-arm64' + + - task: PowerShell@2 + displayName: 'Bundle NuGet' + inputs: + targetType: 'inline' + script: | + + $x64_nupkgs = (Get-ChildItem $(Build.BinariesDirectory)/nuget-artifact-x64 -Filter Microsoft.ML.OnnxRuntime.QNN*.nupkg -Recurse) + $nuget_package_name = $x64_nupkgs[0].Name + $x64_nuget_package = $x64_nupkgs[0].FullName + + $nupkg_unzipped_directory = [System.IO.Path]::Combine($Env:BUILD_ARTIFACTSTAGINGDIRECTORY, 'nuget_unzip_merged', [System.IO.Path]::GetFileNameWithoutExtension($nuget_package_name)) + + $x64_unzip_cmd = "7z.exe x $x64_nuget_package -y -o$nupkg_unzipped_directory" + Invoke-Expression -Command $x64_unzip_cmd + + $arm64_nupkgs = (Get-ChildItem $(Build.BinariesDirectory)/nuget-artifact-arm64 -Filter Microsoft.ML.OnnxRuntime.QNN*.nupkg -Recurse) + $arm64_nuget_package = $arm64_nupkgs[0].FullName + + $arm64_unzip_cmd = "7z.exe x $arm64_nuget_package -y -o$nupkg_unzipped_directory" + Invoke-Expression -Command $arm64_unzip_cmd + + $merged_nuget_path = [System.IO.Path]::Combine($Env:BUILD_ARTIFACTSTAGINGDIRECTORY, 'nuget-artifact-merged') + if (!(Test-Path $merged_nuget_path)) { + New-Item -Path $merged_nuget_path -ItemType Directory + } + + $merged_zip = [System.IO.Path]::Combine($merged_nuget_path, 'qnn_nuget.zip') + $zip_cmd = "7z.exe a -r $merged_zip $nupkg_unzipped_directory/*" + Invoke-Expression -Command $zip_cmd + + $merged_nuget = [System.IO.Path]::Combine($merged_nuget_path, $nuget_package_name) + move $merged_zip $merged_nuget + workingDirectory: $(Build.BinariesDirectory) + + - template: ../templates/esrp_nuget.yml + parameters: + DisplayName: 'ESRP - sign NuGet package' + FolderPath: '$(Build.ArtifactStagingDirectory)/nuget-artifact-merged' + DoEsrp: ${{ parameters.DoEsrp }} + + - task: 1ES.PublishPipelineArtifact@1 + displayName: 'Publish Pipeline NuGet Artifact' + inputs: + artifactName: 'drop-signed-nuget-qnn' + targetPath: '$(Build.ArtifactStagingDirectory)/nuget-artifact-merged' diff --git a/tools/ci_build/github/azure-pipelines/stages/nuget-win-cuda-packaging-stage.yml b/tools/ci_build/github/azure-pipelines/stages/nuget-win-cuda-packaging-stage.yml index bb6b52e16f165..e5d15db5c062a 100644 --- a/tools/ci_build/github/azure-pipelines/stages/nuget-win-cuda-packaging-stage.yml +++ b/tools/ci_build/github/azure-pipelines/stages/nuget-win-cuda-packaging-stage.yml @@ -7,10 +7,6 @@ parameters: type: boolean default: false -- name: DoCompliance - type: boolean - default: true - - name: DoEsrp type: boolean default: true @@ -34,7 +30,7 @@ parameters: displayName: Specific Artifact's BuildId type: string default: '0' - + - name: buildJava type: boolean @@ -43,7 +39,6 @@ stages: - template: ../templates/win-ci.yml parameters: ort_build_pool_name: 'onnxruntime-Win2022-GPU-A10' - DoCompliance: ${{ parameters.DoCompliance }} DoEsrp: ${{ parameters.DoEsrp }} stage_name_suffix: CUDA buildArch: x64 @@ -61,7 +56,6 @@ stages: - template: ../templates/win-ci.yml parameters: ort_build_pool_name: 'onnxruntime-Win2022-GPU-A10' - DoCompliance: ${{ parameters.DoCompliance }} DoEsrp: ${{ parameters.DoEsrp }} stage_name_suffix: TensorRT buildArch: x64 @@ -79,93 +73,90 @@ stages: # Windows CUDA Combined Testing and Publishing - stage: Windows_Packaging_combined_GPU dependsOn: - - Windows_Packaging_CUDA - - Windows_Packaging_TensorRT + - Windows_Packaging_CUDA + - Windows_Packaging_TensorRT condition: succeeded() jobs: - - job: Windows_Packaging_combined_GPU - workspace: - clean: all - pool: 'onnxruntime-Win2022-GPU-A10' - variables: - CUDA_MODULE_LOADINGL: 'LAZY' - GRADLE_OPTS: '-Dorg.gradle.daemon=false' - steps: - - checkout: self # due to checkout multiple repos, the root directory is $(Build.SourcesDirectory)/onnxruntime - - checkout: onnxruntime-inference-examples # due to checkout multiple repos, the root directory is $(Build.SourcesDirectory)/onnxruntime-inference-examples - submodules: false - - - script: dir $(Build.SourcesDirectory) - - template: ../templates/jobs/download_win_gpu_library.yml - parameters: - DownloadCUDA: true - DownloadTRT: true - CudaVersion: ${{ parameters.CudaVersion }} - - - template: ../templates/set-version-number-variables-step.yml - parameters: - versionFileDirectory: '$(Build.SourcesDirectory)\onnxruntime' - workingDirectory: '$(Build.SourcesDirectory)\onnxruntime' - - task: DownloadPipelineArtifact@2 - displayName: 'Download Pipeline Artifact - onnxruntime-win-x64-cuda' - inputs: - artifactName: 'onnxruntime-win-x64-cuda' - targetPath: '$(Build.BinariesDirectory)/zip-artifacts' - - - task: DownloadPipelineArtifact@2 - displayName: 'Download Pipeline Artifact - onnxruntime-win-x64-tensorrt' - inputs: - artifactName: 'onnxruntime-win-x64-tensorrt' - targetPath: '$(Build.BinariesDirectory)/zip-artifacts' - - - task: PowerShell@2 - displayName: 'PowerShell Script' - inputs: - targetType: filePath - filePath: $(Build.SourcesDirectory)\onnxruntime\tools\ci_build\github\windows\extract_zip_files_gpu.ps1 - - - script: | - dir - workingDirectory: '$(Build.BinariesDirectory)/zip-artifacts' - displayName: 'List artifacts' - - - task: BatchScript@1 - displayName: 'Bundle CUDA/TRT EP binaries' - inputs: - filename: $(Build.SourcesDirectory)\onnxruntime\tools\ci_build\github\windows\bundle_dlls_gpu.bat - workingFolder: $(Build.BinariesDirectory)\zip-artifacts - - - task: CopyFiles@2 - displayName: 'Copy zip file to: $(Build.ArtifactStagingDirectory)' - inputs: - SourceFolder: '$(Build.BinariesDirectory)\zip-artifacts' - Contents: 'onnxruntime-win-x64-gpu-*.zip' - TargetFolder: '$(Build.ArtifactStagingDirectory)' - - - template: ../templates/validate-package.yml - parameters: - PackageType: 'zip' - PackagePath: '$(Build.ArtifactStagingDirectory)' - PackageName: 'onnxruntime-win-x64-gpu-$(OnnxRuntimeVersion).zip' - ScriptPath: '$(Build.SourcesDirectory)\onnxruntime\tools\nuget\validate_package.py' - PlatformsSupported: 'win-x64' - VerifyNugetSigning: false - workingDirectory: '$(Build.ArtifactStagingDirectory)' - - - task: BatchScript@1 - displayName: 'Test C API application for GPU package' - inputs: - filename: $(Build.SourcesDirectory)\onnxruntime-inference-examples\c_cxx\squeezenet\run_capi_application.bat - arguments: $(Build.SourcesDirectory)\onnxruntime $(Build.ArtifactStagingDirectory)\onnxruntime-win-x64-gpu-$(OnnxRuntimeVersion).zip $(Build.SourcesDirectory)\onnxruntime-inference-examples\c_cxx\squeezenet - workingFolder: '$(Build.ArtifactStagingDirectory)' - - - task: PublishPipelineArtifact@0 - displayName: 'Publish Pipeline Combined GPU Package Artifact' - inputs: - artifactName: 'onnxruntime-win-x64-gpu' - targetPath: '$(Build.ArtifactStagingDirectory)/onnxruntime-win-x64-gpu-$(OnnxRuntimeVersion).zip' - - - template: ../templates/component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' + - job: Windows_Packaging_combined_GPU + workspace: + clean: all + pool: + name: 'onnxruntime-Win2022-GPU-A10' + variables: + CUDA_MODULE_LOADINGL: 'LAZY' + GRADLE_OPTS: '-Dorg.gradle.daemon=false' + steps: + - checkout: self # due to checkout multiple repos, the root directory is $(Build.SourcesDirectory)/onnxruntime + - checkout: onnxruntime-inference-examples # due to checkout multiple repos, the root directory is $(Build.SourcesDirectory)/onnxruntime-inference-examples + submodules: false + + - script: dir $(Build.SourcesDirectory) + - template: ../templates/jobs/download_win_gpu_library.yml + parameters: + DownloadCUDA: true + DownloadTRT: true + CudaVersion: ${{ parameters.CudaVersion }} + + - template: ../templates/set-version-number-variables-step.yml + parameters: + versionFileDirectory: '$(Build.SourcesDirectory)\onnxruntime' + workingDirectory: '$(Build.SourcesDirectory)\onnxruntime' + - task: DownloadPipelineArtifact@2 + displayName: 'Download Pipeline Artifact - onnxruntime-win-x64-cuda' + inputs: + artifactName: 'onnxruntime-win-x64-cuda' + targetPath: '$(Build.BinariesDirectory)/zip-artifacts' + + - task: DownloadPipelineArtifact@2 + displayName: 'Download Pipeline Artifact - onnxruntime-win-x64-tensorrt' + inputs: + artifactName: 'onnxruntime-win-x64-tensorrt' + targetPath: '$(Build.BinariesDirectory)/zip-artifacts' + + - task: PowerShell@2 + displayName: 'PowerShell Script' + inputs: + targetType: filePath + filePath: $(Build.SourcesDirectory)\onnxruntime\tools\ci_build\github\windows\extract_zip_files_gpu.ps1 + + - script: | + dir + workingDirectory: '$(Build.BinariesDirectory)/zip-artifacts' + displayName: 'List artifacts' + + - task: BatchScript@1 + displayName: 'Bundle CUDA/TRT EP binaries' + inputs: + filename: $(Build.SourcesDirectory)\onnxruntime\tools\ci_build\github\windows\bundle_dlls_gpu.bat + workingFolder: $(Build.BinariesDirectory)\zip-artifacts + + - task: CopyFiles@2 + displayName: 'Copy zip file to: $(Build.ArtifactStagingDirectory)' + inputs: + SourceFolder: '$(Build.BinariesDirectory)\zip-artifacts' + Contents: 'onnxruntime-win-x64-gpu-*.zip' + TargetFolder: '$(Build.ArtifactStagingDirectory)' + + - template: ../templates/validate-package.yml + parameters: + PackageType: 'zip' + PackagePath: '$(Build.ArtifactStagingDirectory)' + PackageName: 'onnxruntime-win-x64-gpu-$(OnnxRuntimeVersion).zip' + ScriptPath: '$(Build.SourcesDirectory)\onnxruntime\tools\nuget\validate_package.py' + PlatformsSupported: 'win-x64' + VerifyNugetSigning: false + workingDirectory: '$(Build.ArtifactStagingDirectory)' + + - task: BatchScript@1 + displayName: 'Test C API application for GPU package' + inputs: + filename: $(Build.SourcesDirectory)\onnxruntime-inference-examples\c_cxx\squeezenet\run_capi_application.bat + arguments: $(Build.SourcesDirectory)\onnxruntime $(Build.ArtifactStagingDirectory)\onnxruntime-win-x64-gpu-$(OnnxRuntimeVersion).zip $(Build.SourcesDirectory)\onnxruntime-inference-examples\c_cxx\squeezenet + workingFolder: '$(Build.ArtifactStagingDirectory)' + + - task: 1ES.PublishPipelineArtifact@1 + displayName: 'Publish Pipeline Combined GPU Package Artifact' + inputs: + artifactName: 'onnxruntime-win-x64-gpu' + targetPath: '$(Build.ArtifactStagingDirectory)' diff --git a/tools/ci_build/github/azure-pipelines/stages/nuget_dml_packaging_stage.yml b/tools/ci_build/github/azure-pipelines/stages/nuget_dml_packaging_stage.yml new file mode 100644 index 0000000000000..093de22566a8b --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/stages/nuget_dml_packaging_stage.yml @@ -0,0 +1,96 @@ +parameters: +- name: DoEsrp + type: boolean + default: true + +stages: +- stage: NuGet_Packaging_DML + dependsOn: + - Windows_CI_GPU_DML_Dev + - Windows_CI_GPU_DML_Dev_x86 + - Windows_CI_GPU_DML_Dev_arm64 + condition: succeeded() + jobs: + - job: NuGet_Packaging_DML + workspace: + clean: all + pool: 'onnxruntime-Win2022-GPU-dml-A10' + steps: + - task: DownloadPipelineArtifact@0 + displayName: 'Download Pipeline Artifact - NuGet DirectML' + inputs: + artifactName: 'drop-nuget-dml' + targetPath: '$(Build.BinariesDirectory)/nuget-artifact-dml' + + - task: DownloadPipelineArtifact@0 + displayName: 'Download Pipeline Artifact - NuGet DirectML x86' + inputs: + artifactName: 'drop-win-dml-x86-zip' + targetPath: '$(Build.BinariesDirectory)/nuget-artifact-dml' + + - task: DownloadPipelineArtifact@0 + displayName: 'Download Pipeline Artifact - NuGet DirectML arm64' + inputs: + artifactName: 'drop-win-dml-arm64-zip' + targetPath: '$(Build.BinariesDirectory)/nuget-artifact-dml' + + - script: | + pushd $(Build.BinariesDirectory)\nuget-artifact-dml + dir + powershell -Command "Invoke-WebRequest http://stahlworks.com/dev/unzip.exe -OutFile unzip.exe" + powershell -Command "Invoke-WebRequest http://stahlworks.com/dev/zip.exe -OutFile zip.exe" + set PATH=%CD%;%PATH% + SETLOCAL EnableDelayedExpansion + FOR /R %%i IN (*.nupkg) do ( + set filename=%%~ni + IF NOT "!filename:~25,7!"=="Managed" ( + rename %%~ni.nupkg %%~ni.zip + unzip %%~ni.zip -d %%~ni + del /Q %%~ni.zip + + unzip win-dml-x86.zip -d win-x86 + mkdir %%~ni\runtimes\win-x86 + mkdir %%~ni\runtimes\win-x86\native + + move win-x86\runtimes\win-x86\native\onnxruntime.dll %%~ni\runtimes\win-x86\native\onnxruntime.dll + move win-x86\runtimes\win-x86\native\onnxruntime.lib %%~ni\runtimes\win-x86\native\onnxruntime.lib + move win-x86\runtimes\win-x86\native\onnxruntime.pdb %%~ni\runtimes\win-x86\native\onnxruntime.pdb + + unzip win-dml-arm64.zip -d win-arm64 + mkdir %%~ni\runtimes\win-arm64 + mkdir %%~ni\runtimes\win-arm64\native + + move win-arm64\runtimes\win-arm64\native\onnxruntime.dll %%~ni\runtimes\win-arm64\native\onnxruntime.dll + move win-arm64\runtimes\win-arm64\native\onnxruntime.lib %%~ni\runtimes\win-arm64\native\onnxruntime.lib + move win-arm64\runtimes\win-arm64\native\onnxruntime.pdb %%~ni\runtimes\win-arm64\native\onnxruntime.pdb + + + pushd %%~ni + zip -r ..\%%~ni.zip . + popd + move %%~ni.zip %%~ni.nupkg + ) + ) + popd + copy $(Build.BinariesDirectory)\nuget-artifact-dml\Microsoft.ML.OnnxRuntime.DirectML*nupkg $(Build.ArtifactStagingDirectory) + displayName: 'Bundle DML NuGet and other binaries' + + - template: ../templates/esrp_nuget.yml + parameters: + DisplayName: 'ESRP - sign NuGet package' + FolderPath: '$(Build.ArtifactStagingDirectory)' + DoEsrp: ${{ parameters.DoEsrp }} + + - template: ../templates/validate-package.yml + parameters: + PackageType: 'nuget' + PackagePath: '$(Build.ArtifactStagingDirectory)' + PackageName: 'Microsoft.ML.OnnxRuntime.DirectML*nupkg' + PlatformsSupported: 'win-x64,win-x86,win-arm64' + VerifyNugetSigning: ${{ parameters.DoEsrp }} + + - task: 1ES.PublishPipelineArtifact@1 + displayName: 'Publish Pipeline NuGet Artifact' + inputs: + artifactName: 'drop-signed-nuget-dml' + targetPath: '$(Build.ArtifactStagingDirectory)' \ No newline at end of file diff --git a/tools/ci_build/github/azure-pipelines/stages/py-cpu-packaging-stage.yml b/tools/ci_build/github/azure-pipelines/stages/py-cpu-packaging-stage.yml index 4ff539df9f914..f5e827e277b40 100644 --- a/tools/ci_build/github/azure-pipelines/stages/py-cpu-packaging-stage.yml +++ b/tools/ci_build/github/azure-pipelines/stages/py-cpu-packaging-stage.yml @@ -59,7 +59,7 @@ parameters: - name: qnn_sdk_version type: string displayName: 'QNN SDK version. Only for QNN packages.' - default: 2.31.0.250130 + default: 2.32.0.250228 stages: - ${{ if eq(parameters.enable_windows_cpu, true) }}: @@ -123,7 +123,7 @@ stages: --skip_submodule_sync --cmake_generator "Visual Studio 17 2022" --enable_pybind - --enable_onnx_tests + --enable_onnx_tests --use_vcpkg --use_vcpkg_ms_internal_asset_cache ${{ parameters.build_py_parameters }} --parallel --use_binskim_compliant_compile_flags --update --build $(TelemetryOption) @@ -151,10 +151,11 @@ stages: Contents: '*.whl' TargetFolder: '$(Build.ArtifactStagingDirectory)' - - task: PublishBuildArtifacts@1 + - task: 1ES.PublishPipelineArtifact@1 displayName: 'Publish Artifact: ONNXRuntime python wheel' inputs: - ArtifactName: onnxruntime + artifactName: onnxruntime-win-$(PythonVersion) + targetPath: '$(Build.ArtifactStagingDirectory)' - script: | 7z x *.whl @@ -185,11 +186,6 @@ stages: workingDirectory: '$(Build.BinariesDirectory)\${{ parameters.cmake_build_type }}\${{ parameters.cmake_build_type }}' displayName: 'Run Python Tests' - - template: ../templates/component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' - - - ${{ if eq(parameters.enable_mac_cpu, true) }}: - stage: Python_Packaging_MacOS dependsOn: [] @@ -199,7 +195,9 @@ stages: workspace: clean: all pool: - vmImage: 'macOS-13' + name: "Azure Pipelines" + image: "macOS-14" + os: macOS variables: MACOSX_DEPLOYMENT_TARGET: '13.3' strategy: @@ -229,7 +227,20 @@ stages: set -e -x export _PYTHON_HOST_PLATFORM=macosx-${{variables.MACOSX_DEPLOYMENT_TARGET}}-universal2 python3 -m pip install -r '$(Build.SourcesDirectory)/tools/ci_build/github/linux/docker/scripts/requirements.txt' - python3 $(Build.SourcesDirectory)/tools/ci_build/build.py --build_dir $(Build.BinariesDirectory) --use_coreml --skip_submodule_sync --parallel --use_vcpkg --use_vcpkg_ms_internal_asset_cache --use_binskim_compliant_compile_flags --config Release --build_wheel ${{ parameters.build_py_parameters }} --use_coreml --cmake_extra_defines CMAKE_OSX_ARCHITECTURES="arm64;x86_64" --update --build + # Note: There is a build error when we set CMAKE_OSX_ARCHITECTURES="arm64;x86_64" and KleidiAI is enabled. + # Disable KleidiAI as a workaround with --no_kleidiai. + # TODO Re-enable KleidiAI once https://github.com/microsoft/onnxruntime/issues/24152 is fixed. + python3 $(Build.SourcesDirectory)/tools/ci_build/build.py \ + --build_dir $(Build.BinariesDirectory) \ + --use_vcpkg --use_vcpkg_ms_internal_asset_cache \ + --use_binskim_compliant_compile_flags \ + --config Release \ + --build_wheel \ + --use_coreml \ + --no_kleidiai \ + ${{ parameters.build_py_parameters }} \ + --cmake_extra_defines CMAKE_OSX_ARCHITECTURES="arm64;x86_64" \ + --update --skip_submodule_sync --build --parallel displayName: 'Command Line Script' - script: | @@ -251,74 +262,76 @@ stages: Contents: '*.whl' TargetFolder: '$(Build.ArtifactStagingDirectory)' - - task: PublishBuildArtifacts@1 + - task: 1ES.PublishPipelineArtifact@1 displayName: 'Publish Artifact: ONNXRuntime python wheel' inputs: - ArtifactName: onnxruntime + artifactName: onnxruntime-macos-$(PythonVersion) + targetPath: '$(Build.ArtifactStagingDirectory)' - - template: ../templates/component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' - - - - ${{ if eq(parameters.enable_linux_arm, true) }}: - - stage: Python_Packaging_Linux_ARM - dependsOn: [] - jobs: - - template: ../templates/py-linux.yml - parameters: - arch: 'aarch64' - machine_pool: 'onnxruntime-linux-ARM64-CPU-2019' - extra_build_arg: ${{ parameters.build_py_parameters }} - cmake_build_type: ${{ parameters.cmake_build_type }} - - - ${{ if eq(parameters.enable_linux_cpu, true) }}: - - stage: Python_Packaging_Linux_CPU - dependsOn: [] - jobs: +- ${{ if eq(parameters.enable_linux_arm, true) }}: + - stage: Python_Packaging_Linux_ARM + dependsOn: [] + jobs: - template: ../templates/py-linux.yml parameters: - arch: 'x86_64' - machine_pool: 'onnxruntime-Ubuntu2204-AMD-CPU-Large' + arch: 'aarch64' + machine_pool: 'onnxruntime-linux-ARM64-CPU-2019' extra_build_arg: ${{ parameters.build_py_parameters }} cmake_build_type: ${{ parameters.cmake_build_type }} + is1ES: true - - ${{ if eq(parameters.enable_windows_arm64_qnn, true) }}: - - stage: Python_Packaging_Windows_ARM64_QNN - dependsOn: [] - jobs: - - template: ../templates/py-win-arm64-qnn.yml +- ${{ if eq(parameters.enable_linux_cpu, true) }}: + - stage: Python_Packaging_Linux_CPU + dependsOn: [] + jobs: + - template: ../templates/py-linux.yml + parameters: + arch: 'x86_64' + machine_pool: 'onnxruntime-Ubuntu2204-AMD-CPU-Large' + extra_build_arg: ${{ parameters.build_py_parameters }} + cmake_build_type: ${{ parameters.cmake_build_type }} + is1ES: true + +- ${{ if eq(parameters.enable_windows_arm64_qnn, true) }}: + - stage: Python_Packaging_Windows_ARM64_QNN + dependsOn: [] + jobs: + - template: ../templates/py-win-arm64-qnn.yml + parameters: + MACHINE_POOL: 'onnxruntime-qnn-windows-vs-2022-arm64' + QNN_SDK: ${{ parameters.qnn_sdk_version }} + BUILD_PY_PARAMETERS: ${{ parameters.build_py_parameters }} + is1ES: true + +- ${{ if eq(parameters.enable_windows_arm64ec_qnn, true) }}: + - stage: Python_Packaging_Windows_arm64ec_QNN + dependsOn: [] + jobs: + - template: ../templates/py-win-arm64ec-qnn.yml parameters: - MACHINE_POOL: 'onnxruntime-qnn-windows-vs-2022-arm64' + MACHINE_POOL: 'Onnxruntime-QNNEP-Windows-2022-CPU' QNN_SDK: ${{ parameters.qnn_sdk_version }} BUILD_PY_PARAMETERS: ${{ parameters.build_py_parameters }} + is1ES: true - - ${{ if eq(parameters.enable_windows_arm64ec_qnn, true) }}: - - stage: Python_Packaging_Windows_arm64ec_QNN - dependsOn: [] - jobs: - - template: ../templates/py-win-arm64ec-qnn.yml - parameters: - MACHINE_POOL: 'Onnxruntime-QNNEP-Windows-2022-CPU' - QNN_SDK: ${{ parameters.qnn_sdk_version }} - BUILD_PY_PARAMETERS: ${{ parameters.build_py_parameters }} - - - ${{ if eq(parameters.enable_windows_x64_qnn, true) }}: - - stage: Python_Packaging_Windows_x64_QNN - dependsOn: [] - jobs: - - template: ../templates/py-win-x64-qnn.yml - parameters: - MACHINE_POOL: 'Onnxruntime-QNNEP-Windows-2022-CPU' - QNN_SDK: ${{ parameters.qnn_sdk_version }} - BUILD_PY_PARAMETERS: ${{ parameters.build_py_parameters }} - - - ${{ if eq(parameters.enable_linux_x64_qnn, true) }}: - - stage: Python_Packaging_Linux_x64_QNN - dependsOn: [] - jobs: - - template: ../templates/py-linux-qnn.yml +- ${{ if eq(parameters.enable_windows_x64_qnn, true) }}: + - stage: Python_Packaging_Windows_x64_QNN + dependsOn: [] + jobs: + - template: ../templates/py-win-x64-qnn.yml parameters: - machine_pool: 'onnxruntime-Ubuntu2204-AMD-CPU' - extra_build_arg: ${{ parameters.build_py_parameters }} - cmake_build_type: ${{ parameters.cmake_build_type }} + MACHINE_POOL: 'Onnxruntime-QNNEP-Windows-2022-CPU' + QNN_SDK: ${{ parameters.qnn_sdk_version }} + BUILD_PY_PARAMETERS: ${{ parameters.build_py_parameters }} + is1ES: true + +- ${{ if eq(parameters.enable_linux_x64_qnn, true) }}: + - stage: Python_Packaging_Linux_x64_QNN + dependsOn: [] + jobs: + - template: ../templates/py-linux-qnn.yml + parameters: + machine_pool: 'onnxruntime-Ubuntu2204-AMD-CPU' + extra_build_arg: ${{ parameters.build_py_parameters }} + cmake_build_type: ${{ parameters.cmake_build_type }} + is1ES: true diff --git a/tools/ci_build/github/azure-pipelines/stages/py-cuda-publishing-stage.yml b/tools/ci_build/github/azure-pipelines/stages/py-cuda-publishing-stage.yml index 1ff43667f4788..fbfbc69bce0a8 100644 --- a/tools/ci_build/github/azure-pipelines/stages/py-cuda-publishing-stage.yml +++ b/tools/ci_build/github/azure-pipelines/stages/py-cuda-publishing-stage.yml @@ -7,13 +7,15 @@ stages: - stage: Python_Publishing_GPU jobs: - job: Python_Publishing_GPU - pool: 'onnxruntime-Ubuntu2204-AMD-CPU' + pool: + name: 'onnxruntime-Ubuntu2204-AMD-CPU' + os: linux steps: - checkout: none - download: build displayName: 'Download Pipeline Artifact' artifact: 'whl' - + - task: UsePythonVersion@0 inputs: versionSpec: '3.13' diff --git a/tools/ci_build/github/azure-pipelines/stages/py-gpu-packaging-stage.yml b/tools/ci_build/github/azure-pipelines/stages/py-gpu-packaging-stage.yml index 362c2a3d74083..eea9b672eef3d 100644 --- a/tools/ci_build/github/azure-pipelines/stages/py-gpu-packaging-stage.yml +++ b/tools/ci_build/github/azure-pipelines/stages/py-gpu-packaging-stage.yml @@ -36,7 +36,6 @@ parameters: displayName: 'CUDA version. Windows Only.' default: '12.2' values: - - 11.8 - 12.2 - name: PythonVersions diff --git a/tools/ci_build/github/azure-pipelines/stages/py-linux-gpu-stage.yml b/tools/ci_build/github/azure-pipelines/stages/py-linux-gpu-stage.yml index 60b2e04e82136..715470eb9f012 100644 --- a/tools/ci_build/github/azure-pipelines/stages/py-linux-gpu-stage.yml +++ b/tools/ci_build/github/azure-pipelines/stages/py-linux-gpu-stage.yml @@ -22,9 +22,8 @@ parameters: - name: cuda_version type: string - default: '11.8' + default: '12.2' values: - - 11.8 - 12.2 stages: diff --git a/tools/ci_build/github/azure-pipelines/stages/py-win-gpu-stage.yml b/tools/ci_build/github/azure-pipelines/stages/py-win-gpu-stage.yml index 32004366fb947..fe2b85976d38b 100644 --- a/tools/ci_build/github/azure-pipelines/stages/py-win-gpu-stage.yml +++ b/tools/ci_build/github/azure-pipelines/stages/py-win-gpu-stage.yml @@ -19,9 +19,8 @@ parameters: default: '' - name: CudaVersion type: string - default: '11.8' + default: '12.2' values: - - 11.8 - 12.2 - name: cmake_build_type diff --git a/tools/ci_build/github/azure-pipelines/stages/set_packaging_variables_stage.yml b/tools/ci_build/github/azure-pipelines/stages/set_packaging_variables_stage.yml index 2e4a673d72e00..a1a983ee9ba20 100644 --- a/tools/ci_build/github/azure-pipelines/stages/set_packaging_variables_stage.yml +++ b/tools/ci_build/github/azure-pipelines/stages/set_packaging_variables_stage.yml @@ -8,6 +8,7 @@ stages: - job: Set_Variables pool: name: 'onnxruntime-Ubuntu2204-AMD-CPU' + os: 'linux' steps: - checkout: none - bash: | @@ -38,9 +39,6 @@ stages: echo "##vso[task.setvariable variable=BuildTime;isOutput=true]$hhmm" displayName: 'Set Start Time as Variable' name: Set_Build_Time - - template: ../templates/component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' - stage: Debug dependsOn: Setup @@ -48,6 +46,7 @@ stages: - job: D1 pool: name: 'onnxruntime-Ubuntu2204-AMD-CPU' + os: 'linux' variables: MyVar: $[stageDependencies.Setup.Set_Variables.outputs['Set_Release_Version_Suffix.ReleaseVersionSuffix']] BuildDate: $[stageDependencies.Setup.Set_Variables.outputs['Set_Build_Date.BuildDate']] @@ -57,6 +56,3 @@ stages: - bash: echo $(MyVar) - bash: echo $(BuildTime) - bash: echo $(BuildDate) - - template: ../templates/component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' diff --git a/tools/ci_build/github/azure-pipelines/templates/android-java-api-aar-test.yml b/tools/ci_build/github/azure-pipelines/templates/android-java-api-aar-test.yml index 3886ceb1ed58f..f5c0cfa68c0c7 100644 --- a/tools/ci_build/github/azure-pipelines/templates/android-java-api-aar-test.yml +++ b/tools/ci_build/github/azure-pipelines/templates/android-java-api-aar-test.yml @@ -17,11 +17,13 @@ parameters: - name: QnnSDKVersion displayName: QNN SDK Version type: string - default: '2.31.0.250130' + default: '2.32.0.250228' jobs: - job: Final_AAR_Testing_Android - pool: 'onnxruntime-Ubuntu2204-AMD-CPU' + pool: + name: 'onnxruntime-Ubuntu2204-AMD-CPU' + os: linux workspace: clean: all variables: @@ -108,8 +110,3 @@ jobs: env: BROWSERSTACK_ID: $(browserstack_username) BROWSERSTACK_TOKEN: $(browserstack_access_key) - - - template: component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' - diff --git a/tools/ci_build/github/azure-pipelines/templates/android-java-api-aar.yml b/tools/ci_build/github/azure-pipelines/templates/android-java-api-aar.yml index cecd6fd912270..f930101f34d05 100644 --- a/tools/ci_build/github/azure-pipelines/templates/android-java-api-aar.yml +++ b/tools/ci_build/github/azure-pipelines/templates/android-java-api-aar.yml @@ -51,14 +51,27 @@ parameters: - name: QnnSDKVersion displayName: QNN SDK Version type: string - default: '2.31.0.250130' + default: '2.32.0.250228' + +- name: is1ES + displayName: Is 1ES pipeline + type: boolean + default: false jobs: - job: Android_Java_API_AAR_Packaging_${{ parameters.job_name_suffix }} timeoutInMinutes: 120 workspace: clean: all - pool: ${{parameters.pool_name}} + pool: + name: ${{ parameters.pool_name }} + ${{ if or(contains(parameters.pool_name, 'ubuntu'), contains(parameters.PoolName, 'linux')) }}: + os: linux + ${{ if contains(parameters.pool_name, 'win')}}: + os: windows + ${{ if contains(parameters.pool_name, 'mac')}}: + os: macOS + variables: artifacts_directory: $(Build.BinariesDirectory)/.artifacts @@ -135,8 +148,13 @@ jobs: - template: jar-maven-signing-linux.yml parameters: JarFileDirectory: '$(artifacts_directory)' - - - task: PublishBuildArtifacts@1 - inputs: - pathtoPublish: '$(artifacts_directory)' - artifactName: '${{parameters.artifactName}}' + - ${{ if eq(parameters.is1ES, false) }}: + - task: PublishPipelineArtifact@1 + inputs: + targetPath: '$(artifacts_directory)' + artifactName: '${{parameters.artifactName}}' + - ${{ if eq(parameters.is1ES, true) }}: + - task: 1ES.PublishPipelineArtifact@1 + inputs: + targetPath: '$(artifacts_directory)' + artifactName: '${{parameters.artifactName}}' diff --git a/tools/ci_build/github/azure-pipelines/templates/c-api-artifacts-package-and-publish-steps-posix.yml b/tools/ci_build/github/azure-pipelines/templates/c-api-artifacts-package-and-publish-steps-posix.yml index 602510424c1a7..c8c20b6a15728 100644 --- a/tools/ci_build/github/azure-pipelines/templates/c-api-artifacts-package-and-publish-steps-posix.yml +++ b/tools/ci_build/github/azure-pipelines/templates/c-api-artifacts-package-and-publish-steps-posix.yml @@ -1,11 +1,11 @@ # sets up common build tools for the windows build machines before build parameters: -- name: buildConfig +- name: buildConfig type: string default: 'Release' -- name: artifactName +- name: artifactName type: string default: 'onnxruntime-linux-x64' @@ -13,28 +13,28 @@ parameters: type: string default: 'onnxruntime-linux-x64' -- name: libraryName +- name: libraryName type: string default: 'libonnxruntime.so' - + steps: - - task: ShellScript@2 - displayName: 'Copy build artifacts for zipping' - inputs: - scriptPath: 'tools/ci_build/github/linux/copy_strip_binary.sh' - args: '-r $(Build.BinariesDirectory) -a ${{parameters.artifactName}} -l ${{parameters.libraryName}} -c ${{parameters.buildConfig}} -s $(Build.SourcesDirectory) -t $(Build.SourceVersion)' - workingDirectory: '$(Build.BinariesDirectory)/${{parameters.buildConfig}}' +- task: ShellScript@2 + displayName: 'Copy build artifacts for zipping' + inputs: + scriptPath: 'tools/ci_build/github/linux/copy_strip_binary.sh' + args: '-r $(Build.BinariesDirectory) -a ${{parameters.artifactName}} -l ${{parameters.libraryName}} -c ${{parameters.buildConfig}} -s $(Build.SourcesDirectory) -t $(Build.SourceVersion)' + workingDirectory: '$(Build.BinariesDirectory)/${{parameters.buildConfig}}' - - task: ArchiveFiles@2 - inputs: - rootFolderOrFile: '$(Build.BinariesDirectory)/${{parameters.artifactName}}' - includeRootFolder: true - archiveType: 'tar' # Options: zip, 7z, tar, wim - tarCompression: 'gz' - archiveFile: '$(Build.ArtifactStagingDirectory)/${{parameters.artifactName}}.tgz' - replaceExistingArchive: true +- task: ArchiveFiles@2 + inputs: + rootFolderOrFile: '$(Build.BinariesDirectory)/${{parameters.artifactName}}' + includeRootFolder: true + archiveType: 'tar' # Options: zip, 7z, tar, wim + tarCompression: 'gz' + archiveFile: '$(Build.ArtifactStagingDirectory)/${{parameters.artifactName}}.tgz' + replaceExistingArchive: true - - task: PublishPipelineArtifact@1 - inputs: - targetPath: '$(Build.ArtifactStagingDirectory)' - artifactName: '${{parameters.artifactNameNoVersionString}}' +- task: 1ES.PublishPipelineArtifact@1 + inputs: + targetPath: '$(Build.ArtifactStagingDirectory)' + artifactName: '${{parameters.artifactNameNoVersionString}}' diff --git a/tools/ci_build/github/azure-pipelines/templates/c-api-artifacts-package-and-publish-steps-windows.yml b/tools/ci_build/github/azure-pipelines/templates/c-api-artifacts-package-and-publish-steps-windows.yml index 5ee425405ac70..046c737a2b151 100644 --- a/tools/ci_build/github/azure-pipelines/templates/c-api-artifacts-package-and-publish-steps-windows.yml +++ b/tools/ci_build/github/azure-pipelines/templates/c-api-artifacts-package-and-publish-steps-windows.yml @@ -57,6 +57,22 @@ steps: copy $(Build.BinariesDirectory)\${{parameters.buildConfig}}\${{parameters.buildConfig}}\onnxruntime_providers_cuda.pdb $(Build.BinariesDirectory)\${{parameters.artifactName}}\lib copy $(Build.BinariesDirectory)\${{parameters.buildConfig}}\${{parameters.buildConfig}}\onnxruntime_providers_cuda.lib $(Build.BinariesDirectory)\${{parameters.artifactName}}\lib + # Copy WebGPU dependencies if required + copy $(Build.BinariesDirectory)\${{parameters.buildConfig}}\${{parameters.buildConfig}}\dxcompiler.dll $(Build.BinariesDirectory)\${{parameters.artifactName}}\lib + copy $(Build.BinariesDirectory)\${{parameters.buildConfig}}\${{parameters.buildConfig}}\dxil.dll $(Build.BinariesDirectory)\${{parameters.artifactName}}\lib + + # Copy QNN dependencies if required + copy $(Build.BinariesDirectory)\${{parameters.buildConfig}}\${{parameters.buildConfig}}\onnxruntime_providers_qnn.dll $(Build.BinariesDirectory)\${{parameters.artifactName}}\lib + copy $(Build.BinariesDirectory)\${{parameters.buildConfig}}\${{parameters.buildConfig}}\libQnnHtp*.so $(Build.BinariesDirectory)\${{parameters.artifactName}}\lib /Y + copy $(Build.BinariesDirectory)\${{parameters.buildConfig}}\${{parameters.buildConfig}}\libqnnhtp*.cat $(Build.BinariesDirectory)\${{parameters.artifactName}}\lib /Y + copy $(Build.BinariesDirectory)\${{parameters.buildConfig}}\${{parameters.buildConfig}}\QnnCpu.dll $(Build.BinariesDirectory)\${{parameters.artifactName}}\lib + copy $(Build.BinariesDirectory)\${{parameters.buildConfig}}\${{parameters.buildConfig}}\QnnHtp.dll $(Build.BinariesDirectory)\${{parameters.artifactName}}\lib + copy $(Build.BinariesDirectory)\${{parameters.buildConfig}}\${{parameters.buildConfig}}\QnnHtpPrepare.dll $(Build.BinariesDirectory)\${{parameters.artifactName}}\lib + copy $(Build.BinariesDirectory)\${{parameters.buildConfig}}\${{parameters.buildConfig}}\QnnHtpV68Stub.dll $(Build.BinariesDirectory)\${{parameters.artifactName}}\lib + copy $(Build.BinariesDirectory)\${{parameters.buildConfig}}\${{parameters.buildConfig}}\QnnHtpV73Stub.dll $(Build.BinariesDirectory)\${{parameters.artifactName}}\lib + copy $(Build.BinariesDirectory)\${{parameters.buildConfig}}\${{parameters.buildConfig}}\QnnSaver.dll $(Build.BinariesDirectory)\${{parameters.artifactName}}\lib + copy $(Build.BinariesDirectory)\${{parameters.buildConfig}}\${{parameters.buildConfig}}\QnnSystem.dll $(Build.BinariesDirectory)\${{parameters.artifactName}}\lib + # copy trt ep libraries only when trt ep is enabled copy $(Build.BinariesDirectory)\${{parameters.buildConfig}}\${{parameters.buildConfig}}\onnxruntime_providers_tensorrt.dll $(Build.BinariesDirectory)\${{parameters.artifactName}}\lib copy $(Build.BinariesDirectory)\${{parameters.buildConfig}}\${{parameters.buildConfig}}\onnxruntime_providers_tensorrt.pdb $(Build.BinariesDirectory)\${{parameters.artifactName}}\lib @@ -95,7 +111,7 @@ steps: archiveFile: '$(Build.ArtifactStagingDirectory)\${{parameters.artifactName}}.zip' replaceExistingArchive: true - - task: PublishPipelineArtifact@1 + - task: 1ES.PublishPipelineArtifact@1 inputs: - targetPath: '$(Build.ArtifactStagingDirectory)\${{parameters.artifactName}}.zip' + targetPath: '$(Build.ArtifactStagingDirectory)' artifactName: '${{parameters.artifactNameNoVersionString}}' diff --git a/tools/ci_build/github/azure-pipelines/templates/c-api-cpu.yml b/tools/ci_build/github/azure-pipelines/templates/c-api-cpu.yml index a6fe5ac27749b..9b1d7b705e741 100644 --- a/tools/ci_build/github/azure-pipelines/templates/c-api-cpu.yml +++ b/tools/ci_build/github/azure-pipelines/templates/c-api-cpu.yml @@ -3,12 +3,6 @@ parameters: displayName: Run Tests? type: boolean default: true - -- name: DoCompliance - displayName: Run Compliance Tasks? - type: boolean - default: true - - name: DoEsrp displayName: Run code sign tasks? Must be true if you are doing an Onnx Runtime release. type: boolean @@ -51,7 +45,12 @@ parameters: - name: QnnSDKVersion displayName: QNN SDK Version type: string - default: 2.31.0.250130 + default: 2.32.0.250228 + +- name: is1ES + displayName: Is 1ES pipeline + type: boolean + default: false stages: - template: linux-cpu-packaging-pipeline.yml @@ -81,6 +80,7 @@ stages: enable_code_sign: ${{ parameters.DoEsrp }} packageName: 'onnxruntime-android' ReleaseVersionSuffix: $(ReleaseVersionSuffix) + is1ES: ${{ parameters.is1ES }} - stage: Android_Java_API_AAR_Testing_Full dependsOn: Android_Java_API_AAR_Packaging_Full @@ -106,6 +106,7 @@ stages: packageName: 'onnxruntime-android-qnn' ReleaseVersionSuffix: $(ReleaseVersionSuffix) QnnSDKVersion: ${{ parameters.QnnSDKVersion }} + is1ES: ${{ parameters.is1ES }} - stage: Final_AAR_Testing_Android_QNN dependsOn: Android_Java_API_AAR_Packaging_QNN @@ -123,7 +124,10 @@ stages: workspace: clean: all pool: - vmImage: 'macOS-13' + name: 'Azure Pipelines' + image: 'macOS-14' + os: 'macOS' + timeoutInMinutes: 300 steps: - template: set-version-number-variables-step.yml @@ -152,18 +156,15 @@ stages: --mac_catalyst_enabled displayName: "Test Apple framework" - - task: PublishBuildArtifacts@1 + - task: 1ES.PublishPipelineArtifact@1 inputs: - pathtoPublish: '$(Build.BinariesDirectory)/artifacts' + targetPath: '$(Build.BinariesDirectory)/artifacts' artifactName: 'onnxruntime-ios-full-xcframework' - - template: component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' + - template: win-ci.yml parameters: - DoCompliance: ${{ parameters.DoCompliance }} DoEsrp: ${{ parameters.DoEsrp }} stage_name_suffix: CPU_x86_${{ parameters.BuildVariant }} buildArch: x86 @@ -176,29 +177,27 @@ stages: - template: win-ci.yml parameters: - DoCompliance: ${{ parameters.DoCompliance }} DoEsrp: ${{ parameters.DoEsrp }} stage_name_suffix: CPU_arm64_${{ parameters.BuildVariant }} buildArch: x64 msbuildPlatform: arm64 packageName: arm64 - buildparameter: --build_nodejs --arm64 ${{ parameters.AdditionalBuildFlags }} ${{ parameters.AdditionalWinBuildFlags}} + buildparameter: --arm64 ${{ parameters.AdditionalBuildFlags }} ${{ parameters.AdditionalWinBuildFlags}} runTests: false buildJava: false - buildNodejs: true + buildNodejs: false - template: win-ci.yml parameters: - DoCompliance: ${{ parameters.DoCompliance }} DoEsrp: ${{ parameters.DoEsrp }} stage_name_suffix: CPU_x64_${{ parameters.BuildVariant }} buildArch: x64 msbuildPlatform: x64 packageName: x64 - buildparameter: --build_java --build_nodejs ${{ parameters.AdditionalBuildFlags }} ${{ parameters.AdditionalWinBuildFlags}} + buildparameter: --build_java ${{ parameters.AdditionalBuildFlags }} ${{ parameters.AdditionalWinBuildFlags}} runTests: ${{ parameters.RunOnnxRuntimeTests }} buildJava: true - buildNodejs: true + buildNodejs: false - stage: Jar_Packaging dependsOn: @@ -282,15 +281,13 @@ stages: SourceFolder: '$(Build.BinariesDirectory)\java-artifact\onnxruntime-java-win-x64' TargetFolder: '$(Build.ArtifactStagingDirectory)' - - task: PublishPipelineArtifact@1 + - task: 1ES.PublishPipelineArtifact@1 displayName: 'Publish Pipeline Artifact' inputs: targetPath: '$(Build.ArtifactStagingDirectory)' - artifact: 'onnxruntime-java' + artifactName: 'onnxruntime-java' + - - template: component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' - stage: NuGet_Packaging_CPU dependsOn: @@ -312,8 +309,8 @@ stages: OrtPackageId: ${{ parameters.OrtNugetPackageId }} breakCodesignValidationInjection: ${{ parameters.DoEsrp }} ReleaseVersionSuffix: $[stageDependencies.Setup.Set_Variables.outputs['Set_Release_Version_Suffix.ReleaseVersionSuffix']] - BuildDate : $[stageDependencies.Setup.Set_Variables.outputs['Set_Build_Date.BuildDate']] - BuildTime : $[stageDependencies.Setup.Set_Variables.outputs['Set_Build_Time.BuildTime']] + BuildDate: $[stageDependencies.Setup.Set_Variables.outputs['Set_Build_Date.BuildDate']] + BuildTime: $[stageDependencies.Setup.Set_Variables.outputs['Set_Build_Time.BuildTime']] steps: - checkout: self @@ -384,7 +381,7 @@ stages: BuildId: ${{ parameters.BuildId }} - script: | - dir + dir workingDirectory: '$(Build.BinariesDirectory)/nuget-artifact' displayName: 'List artifacts' @@ -398,7 +395,7 @@ stages: filePath: $(Build.SourcesDirectory)\tools\ci_build\github\windows\extract_nuget_files.ps1 - script: | - mklink /D /J models C:\local\models + mklink /D /J models C:\local\models workingDirectory: '$(Build.BinariesDirectory)' displayName: 'Create models link' - task: NuGetToolInstaller@0 @@ -488,7 +485,7 @@ stages: PlatformsSupported: 'win-x64,win-x86,linux-x64,linux-arm64,osx-x64' VerifyNugetSigning: false - - task: PublishPipelineArtifact@0 + - task: 1ES.PublishPipelineArtifact@1 displayName: 'Publish Pipeline NuGet Artifact' inputs: artifactName: 'drop-signed-nuget-CPU' @@ -504,21 +501,16 @@ stages: msbuildArguments: '-t:Clean -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId=$(OrtPackageId)' workingDirectory: '$(Build.SourcesDirectory)\csharp' - - template: component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' + - stage: Nodejs_Packaging dependsOn: - - Windows_CI_GPU_DML_Dev - - Windows_CI_GPU_DML_Dev_arm64 + - Windows_Nodejs_Packaging_x64 + - Windows_Nodejs_Packaging_arm64 + - Linux_Nodejs_Packaging_x64 - Linux_C_API_Packaging_CPU - - Linux_C_API_Packaging_GPU - MacOS_C_API_Package_Publish - - Windows_Packaging_CPU_x86_${{ parameters.BuildVariant }} - - Windows_Packaging_CPU_x64_${{ parameters.BuildVariant }} - - Windows_Packaging_CPU_arm64_${{ parameters.BuildVariant }} condition: succeeded() jobs: - job: Nodejs_Packaging @@ -537,11 +529,11 @@ stages: submodules: true - script: | - echo.>>.gitattributes - echo /js/** text=auto eol=lf>>.gitattributes - rd /s /q js - git checkout -- js/** - git checkout -- .gitattributes + echo.>>.gitattributes + echo /js/** text=auto eol=lf>>.gitattributes + rd /s /q js + git checkout -- js/** + git checkout -- .gitattributes workingDirectory: '$(Build.SourcesDirectory)' displayName: 'Testing: force EOL to lf on windows for /js/**' @@ -549,74 +541,78 @@ stages: # Node.js binding artifacts preparation # # This stage prepares Node.js binding artifacts for publishing. The artifacts support the following platforms: - # - Windows x64 with DML support - # - Windows arm64 with DML support - # - Linux x64 with TensorRT support + # - Windows x64 (CPU, DML, WebGPU) + # - Windows arm64 (CPU, DML, WebGPU) + # - Linux x64 (CPU, CUDA, TensorRT, WebGPU) # - Linux arm64 (CPU only) - # - macOS x64 (CPU only) - # - macOS arm64 (CPU only) + # - macOS x64 (CPU, CoreML, WebGPU) + # - macOS arm64 (CPU, CoreML, WebGPU) # - # ORT Node.js binding artifacts contain 2 parts: - # 1. ONNX Runtime native shared libraries and their dependencies - # - Windows (x64, arm64): - # - onnxruntime.dll - # - DirectML.dll - # - Linux (x64, arm64): - # - libonnxruntime.so{.version} - # - libonnxruntime_providers_shared.so - # - libonnxruntime_providers_{provider}.so - # - macOS (x64, arm64): - # - libonnxruntime.dylib - # 2. ONNX Runtime Node.js binding - # - onnxruntime_binding.node + # File manifest: + # - Windows x64 (CPU, DML, WebGPU): + # dependency: Windows_Nodejs_Packaging_x64 (drop-onnxruntime-nodejs-win-x64) + # files: + # - onnxruntime_binding.node + # - onnxruntime.dll + # - DirectML.dll + # - dxil.dll + # - dxcompiler.dll # - # For windows platform, the artifact is named as 'onnxruntime-nodejs-win-x64-dml' for x64, and - # 'onnxruntime-nodejs-win-arm64-dml' for arm64. Each artifact contains both (1) and (2). + # - Windows arm64 (CPU, DML, WebGPU): + # dependency: Windows_Nodejs_Packaging_arm64 (drop-onnxruntime-nodejs-win-arm64) + # files: + # - onnxruntime_binding.node + # - onnxruntime.dll + # - DirectML.dll + # - dxil.dll + # - dxcompiler.dll # - # For Linux and macOS platforms, (1) and (2) are packed into separate artifacts. - # The following artifacts contain (1): - # - onnxruntime-osx - # - onnxruntime-linux-x64-tensorrt - # - onnxruntime-linux-aarch64 - # The following artifacts contain (2): - # - drop-onnxruntime-nodejs-linux-x64-tensorrt - # - drop-onnxruntime-nodejs-linux-aarch64 - # - drop-onnxruntime-nodejs-osx-x86_64 - # - drop-onnxruntime-nodejs-osx-arm64 + # - Linux x64 (CPU, CUDA, TensorRT, WebGPU): + # dependency: Linux_Nodejs_Packaging_x64 (drop-onnxruntime-nodejs-linux-x64) + # files: + # - onnxruntime_binding.node + # - libonnxruntime.so.1 + # - libonnxruntime_providers_shared.so + # - libonnxruntime_providers_cuda.so + # - libonnxruntime_providers_tensorrt.so # - # All binary artifacts will eventually be put into folder before packaging 'onnxruntime-node': + # - Linux arm64 (CPU only): + # dependency: Linux_C_API_Packaging_CPU_aarch64 (drop-onnxruntime-nodejs-linux-aarch64) + # files: + # - onnxruntime_binding.node + # - libonnxruntime.so.1 + # + # - macOS x64 (CPU, CoreML, WebGPU): + # dependency: MacOS_C_API_Packaging_CPU_x86_64 (drop-onnxruntime-nodejs-osx-x86_64) + # files: + # - onnxruntime_binding.node + # - libonnxruntime.{version}.dylib + # + # - macOS arm64 (CPU, CoreML, WebGPU): + # dependency: MacOS_C_API_Packaging_CPU_arm64 (drop-onnxruntime-nodejs-osx-arm64) + # files: + # - onnxruntime_binding.node + # - libonnxruntime.{version}.dylib + # + # The following files will be excluded from the further packaging because they are too large to be included in the + # NPM package: + # - linux/x64/libonnxruntime_providers_cuda.so + # + # Rest binary artifacts will eventually be put into folder before packaging 'onnxruntime-node': # $(Build.SourcesDirectory)\js\node\bin\napi-v3\{os}\{cpu_arch}\ # # {os} is one of 'win32', 'darwin', 'linux' and {cpu_arch} is one of 'x64', 'arm64'. - - task: DownloadPipelineArtifact@0 - displayName: 'Download Pipeline Artifact - NuGet (OSX)' - inputs: - artifactName: 'onnxruntime-osx' - targetPath: '$(Build.BinariesDirectory)/nuget-artifact' - - - task: DownloadPipelineArtifact@0 - displayName: 'Download Pipeline Artifact - NuGet (Linux x64)' - inputs: - artifactName: 'onnxruntime-linux-x64-tensorrt' - targetPath: '$(Build.BinariesDirectory)/nuget-artifact' - - - task: DownloadPipelineArtifact@0 - displayName: 'Download Pipeline Artifact - NuGet (Linux aarch64)' - inputs: - artifactName: 'onnxruntime-linux-aarch64' - targetPath: '$(Build.BinariesDirectory)/nuget-artifact' - - task: DownloadPipelineArtifact@0 displayName: 'Download Pipeline Artifact - Nodejs (Win x64)' inputs: - artifactName: 'drop-onnxruntime-nodejs-win-x64-dml' + artifactName: 'drop-onnxruntime-nodejs-win-x64' targetPath: '$(Build.BinariesDirectory)/nodejs-artifacts/win32/x64/' - task: DownloadPipelineArtifact@0 displayName: 'Download Pipeline Artifact - Nodejs (Win ARM64)' inputs: - artifactName: 'drop-onnxruntime-nodejs-win-arm64-dml' + artifactName: 'drop-onnxruntime-nodejs-win-arm64' targetPath: '$(Build.BinariesDirectory)/nodejs-artifacts/win32/arm64/' - task: DownloadPipelineArtifact@0 @@ -634,7 +630,7 @@ stages: - task: DownloadPipelineArtifact@0 displayName: 'Download Pipeline Artifact - Nodejs (Linux x64)' inputs: - artifactName: 'drop-onnxruntime-nodejs-linux-x64-tensorrt' + artifactName: 'drop-onnxruntime-nodejs-linux-x64' targetPath: '$(Build.BinariesDirectory)/nodejs-artifacts/linux/x64/' - task: DownloadPipelineArtifact@0 @@ -643,27 +639,21 @@ stages: artifactName: 'drop-onnxruntime-nodejs-linux-aarch64' targetPath: '$(Build.BinariesDirectory)/nodejs-artifacts/linux/arm64/' - - task: PowerShell@2 - displayName: 'PowerShell Script' - inputs: - targetType: filePath - filePath: $(Build.SourcesDirectory)\tools\ci_build\github\windows\extract_nuget_files.ps1 - - script: | - dir - workingDirectory: '$(Build.BinariesDirectory)/nuget-artifact' + dir /S + workingDirectory: '$(Build.BinariesDirectory)/nodejs-artifacts' displayName: 'List artifacts' - script: | - npm ci + npm ci workingDirectory: '$(Build.SourcesDirectory)/js' displayName: 'Install NPM packages /js' - script: | - npm ci + npm ci workingDirectory: '$(Build.SourcesDirectory)/js/common' displayName: 'Install NPM packages /js/common' - script: | - npm ci + npm ci workingDirectory: '$(Build.SourcesDirectory)/js/node' displayName: 'Install NPM packages /js/node' @@ -688,61 +678,43 @@ stages: TargetFolder: '$(Build.SourcesDirectory)\js\node\bin\napi-v3\win32\arm64' # Node.js binding linux/x64 - - task: CopyFiles@2 - displayName: 'Copy nuget binaries to: $(Build.SourcesDirectory)\js\node\bin\napi-v3\linux\x64\' - inputs: - SourceFolder: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\nuget-artifacts\onnxruntime-linux-x64-tensorrt\lib' - Contents: | - libonnxruntime.so.* - libonnxruntime_providers_shared.so - TargetFolder: '$(Build.SourcesDirectory)\js\node\bin\napi-v3\linux\x64' - task: CopyFiles@2 displayName: 'Copy nodejs binaries to: $(Build.SourcesDirectory)\js\node\bin\napi-v3\linux\x64\' inputs: SourceFolder: '$(Build.BinariesDirectory)\nodejs-artifacts\linux\x64' - Contents: '*.node' + Contents: | + libonnxruntime.so.1 + *.node TargetFolder: '$(Build.SourcesDirectory)\js\node\bin\napi-v3\linux\x64' # Node.js binding linux/arm64 - - task: CopyFiles@2 - displayName: 'Copy nuget binaries to: $(Build.SourcesDirectory)\js\node\bin\napi-v3\linux\arm64\' - inputs: - SourceFolder: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\nuget-artifacts\onnxruntime-linux-aarch64\lib' - Contents: 'libonnxruntime.so.*' - TargetFolder: '$(Build.SourcesDirectory)\js\node\bin\napi-v3\linux\arm64' - task: CopyFiles@2 displayName: 'Copy nodejs binaries to: $(Build.SourcesDirectory)\js\node\bin\napi-v3\linux\arm64\' inputs: SourceFolder: '$(Build.BinariesDirectory)\nodejs-artifacts\linux\arm64' - Contents: '*.node' + Contents: | + libonnxruntime.so.1 + *.node TargetFolder: '$(Build.SourcesDirectory)\js\node\bin\napi-v3\linux\arm64' # Node.js binding darwin/x64 - - task: CopyFiles@2 - displayName: 'Copy nuget binaries to: $(Build.SourcesDirectory)\js\node\bin\napi-v3\darwin\x64\' - inputs: - SourceFolder: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\nuget-artifacts\onnxruntime-osx-x86_64\lib' - Contents: 'libonnxruntime.*.dylib' - TargetFolder: '$(Build.SourcesDirectory)\js\node\bin\napi-v3\darwin\x64' - task: CopyFiles@2 displayName: 'Copy nodejs binaries to: $(Build.SourcesDirectory)\js\node\bin\napi-v3\darwin\x64\' inputs: SourceFolder: '$(Build.BinariesDirectory)\nodejs-artifacts\darwin\x64' - Contents: '*.node' + Contents: | + libonnxruntime.*.dylib + *.node TargetFolder: '$(Build.SourcesDirectory)\js\node\bin\napi-v3\darwin\x64' # Node.js binding darwin/arm64 - - task: CopyFiles@2 - displayName: 'Copy nuget binaries to: $(Build.SourcesDirectory)\js\node\bin\napi-v3\darwin\arm64\' - inputs: - SourceFolder: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\nuget-artifacts\onnxruntime-osx-arm64\lib' - Contents: 'libonnxruntime.*.dylib' - TargetFolder: '$(Build.SourcesDirectory)\js\node\bin\napi-v3\darwin\arm64' - task: CopyFiles@2 displayName: 'Copy nodejs binaries to: $(Build.SourcesDirectory)\js\node\bin\napi-v3\darwin\arm64\' inputs: SourceFolder: '$(Build.BinariesDirectory)\nodejs-artifacts\darwin\arm64' - Contents: '*.node' + Contents: | + libonnxruntime.*.dylib + *.node TargetFolder: '$(Build.SourcesDirectory)\js\node\bin\napi-v3\darwin\arm64' - task: PowerShell@2 @@ -767,52 +739,57 @@ stages: Contents: 'onnxruntime-node-*.tgz' TargetFolder: '$(Build.ArtifactStagingDirectory)' - - task: PublishPipelineArtifact@0 + - task: 1ES.PublishPipelineArtifact@1 displayName: 'Publish NPM packages files' inputs: artifactName: 'NPM_packages' targetPath: '$(Build.ArtifactStagingDirectory)' - - template: component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' + - template: ../nuget/templates/test_win.yml + parameters: + AgentPool: 'onnxruntime-Win-CPU-2022' + Skipx86Tests: false + NugetPackageName: 'Microsoft.ML.OnnxRuntime' + ArtifactSuffix: 'CPU' + SpecificArtifact: ${{ parameters.SpecificArtifact }} + BuildId: ${{ parameters.BuildId }} + +- template: ../nuget/templates/test_android.yml parameters: AgentPool : 'onnxruntime-Win-CPU-2022' - Skipx86Tests : false - NugetPackageName : 'Microsoft.ML.OnnxRuntime' ArtifactSuffix: 'CPU' SpecificArtifact: ${{ parameters.SpecificArtifact }} BuildId: ${{ parameters.BuildId }} - template: ../nuget/templates/test_linux.yml parameters: - AgentPool : onnxruntime-Ubuntu2204-AMD-CPU - NugetPackageName : 'Microsoft.ML.OnnxRuntime' + AgentPool: onnxruntime-Ubuntu2204-AMD-CPU + NugetPackageName: 'Microsoft.ML.OnnxRuntime' ArtifactSuffix: 'CPU' SpecificArtifact: ${{ parameters.SpecificArtifact }} BuildId: ${{ parameters.BuildId }} - template: ../nuget/templates/test_macos.yml parameters: - AgentPool : macOS-13 + AgentPool: macOS-14 ArtifactSuffix: 'CPU' - template: ../nodejs/templates/test_win.yml parameters: - AgentPool : 'onnxruntime-Win-CPU-2022' - StageSuffix : 'Win_CPU_x64' + AgentPool: 'onnxruntime-Win-CPU-2022' + StageSuffix: 'Win_CPU_x64' - template: ../nodejs/templates/test_linux.yml parameters: - AgentPool : 'Azure-Pipelines-EO-Ubuntu-2004-aiinfra' - StageSuffix : 'Linux_CPU_x64' + AgentPool: 'onnxruntime-Ubuntu2204-AMD-CPU' + StageSuffix: 'Linux_CPU_x64' - template: ../nodejs/templates/test_macos.yml parameters: - StageSuffix : 'macOS_CPU_x64' + StageSuffix: 'macOS_CPU_x64' - template: final-jar-testing.yml parameters: @@ -833,4 +810,4 @@ stages: OS: MacOS BuildId: ${{ parameters.BuildId }} SpecificArtifact: ${{ parameters.SpecificArtifact }} - PoolName: 'macOS-13' + PoolName: 'macOS-14' diff --git a/tools/ci_build/github/azure-pipelines/templates/c-api-linux-cpu.yml b/tools/ci_build/github/azure-pipelines/templates/c-api-linux-cpu.yml index 330369ed0cc7a..cd2997cc389e9 100644 --- a/tools/ci_build/github/azure-pipelines/templates/c-api-linux-cpu.yml +++ b/tools/ci_build/github/azure-pipelines/templates/c-api-linux-cpu.yml @@ -35,68 +35,68 @@ jobs: workspace: clean: all - timeoutInMinutes: 210 - pool: ${{parameters.PoolName}} + timeoutInMinutes: 210 + pool: + name: ${{parameters.PoolName}} + os: linux + ${{ if eq(parameters.OnnxruntimeArch, 'aarch64') }}: + hostArchitecture: Arm64 steps: - - checkout: self - clean: true - submodules: none - - template: set-version-number-variables-step.yml - - ${{ if eq(parameters.OnnxruntimeArch, 'x64') }}: - - template: get-docker-image-steps.yml - parameters: - Dockerfile: tools/ci_build/github/linux/docker/inference/x86_64/default/cpu/Dockerfile - Context: tools/ci_build/github/linux/docker/inference/x86_64/default/cpu - DockerBuildArgs: "--build-arg BUILD_UID=$( id -u )" - Repository: onnxruntimecpubuildcentos8${{parameters.OnnxruntimeArch}}_packaging - - - ${{ if eq(parameters.OnnxruntimeArch, 'aarch64') }}: - - template: get-docker-image-steps.yml - parameters: - Dockerfile: tools/ci_build/github/linux/docker/inference/aarch64/default/cpu/Dockerfile - Context: tools/ci_build/github/linux/docker/inference/aarch64/default/cpu - DockerBuildArgs: "--build-arg BUILD_UID=$( id -u )" - Repository: onnxruntimecpubuildcentos8${{parameters.OnnxruntimeArch}}_packaging + - checkout: self + clean: true + submodules: none + - template: set-version-number-variables-step.yml + - ${{ if eq(parameters.OnnxruntimeArch, 'x64') }}: + - template: get-docker-image-steps.yml + parameters: + Dockerfile: tools/ci_build/github/linux/docker/inference/x86_64/default/cpu/Dockerfile + Context: tools/ci_build/github/linux/docker/inference/x86_64/default/cpu + DockerBuildArgs: "--build-arg BUILD_UID=$( id -u )" + Repository: onnxruntimecpubuildcentos8${{parameters.OnnxruntimeArch}}_packaging - - task: CmdLine@2 - inputs: - script: | - set -e -x - mkdir -p $HOME/.onnx - docker run -e SYSTEM_COLLECTIONURI --rm --volume /data/onnx:/data/onnx:ro --volume $(Build.SourcesDirectory):/onnxruntime_src --volume $(Build.BinariesDirectory):/build \ - --volume $HOME/.onnx:/home/onnxruntimedev/.onnx -e NIGHTLY_BUILD onnxruntimecpubuildcentos8${{parameters.OnnxruntimeArch}}_packaging /bin/bash -c "python3 \ - /onnxruntime_src/tools/ci_build/build.py --enable_lto --build_java --build_nodejs --build_dir /build --config Release \ - --skip_submodule_sync --parallel --use_vcpkg --use_vcpkg_ms_internal_asset_cache --use_binskim_compliant_compile_flags --use_vcpkg --use_vcpkg_ms_internal_asset_cache --build_shared_lib ${{ parameters.AdditionalBuildFlags }} && cd /build/Release && make install DESTDIR=/build/installed" - mkdir $(Build.ArtifactStagingDirectory)/testdata - cp $(Build.BinariesDirectory)/Release/libcustom_op_library.so* $(Build.ArtifactStagingDirectory)/testdata - ls -al $(Build.ArtifactStagingDirectory) - displayName: 'Create Artifacts' + - ${{ if eq(parameters.OnnxruntimeArch, 'aarch64') }}: + - template: get-docker-image-steps.yml + parameters: + Dockerfile: tools/ci_build/github/linux/docker/inference/aarch64/default/cpu/Dockerfile + Context: tools/ci_build/github/linux/docker/inference/aarch64/default/cpu + DockerBuildArgs: "--build-arg BUILD_UID=$( id -u )" + Repository: onnxruntimecpubuildcentos8${{parameters.OnnxruntimeArch}}_packaging - - ${{ if eq(parameters.PackageJava, 'true') }}: - - template: java-api-artifacts-package-and-publish-steps-posix.yml - parameters: - arch: 'linux-${{parameters.OnnxruntimeArch}}' - buildConfig: 'Release' - artifactName: 'onnxruntime-java-linux-${{parameters.OnnxruntimeArch}}' - version: '$(OnnxRuntimeVersion)' - libraryName: 'libonnxruntime.so' - nativeLibraryName: 'libonnxruntime4j_jni.so' + - task: CmdLine@2 + inputs: + script: | + set -e -x + mkdir -p $HOME/.onnx + docker run -e SYSTEM_COLLECTIONURI --rm --volume /data/onnx:/data/onnx:ro --volume $(Build.SourcesDirectory):/onnxruntime_src --volume $(Build.BinariesDirectory):/build \ + --volume $HOME/.onnx:/home/onnxruntimedev/.onnx -e NIGHTLY_BUILD onnxruntimecpubuildcentos8${{parameters.OnnxruntimeArch}}_packaging /bin/bash -c "python3 \ + /onnxruntime_src/tools/ci_build/build.py --enable_lto --build_java --build_nodejs --build_dir /build --config Release \ + --skip_submodule_sync --parallel --use_vcpkg --use_vcpkg_ms_internal_asset_cache --use_binskim_compliant_compile_flags --use_vcpkg --use_vcpkg_ms_internal_asset_cache --build_shared_lib ${{ parameters.AdditionalBuildFlags }} && cd /build/Release && make install DESTDIR=/build/installed" + mkdir $(Build.ArtifactStagingDirectory)/testdata + cp $(Build.BinariesDirectory)/Release/libcustom_op_library.so* $(Build.ArtifactStagingDirectory)/testdata + ls -al $(Build.ArtifactStagingDirectory) + displayName: 'Create Artifacts' - - template: c-api-artifacts-package-and-publish-steps-posix.yml + - ${{ if eq(parameters.PackageJava, 'true') }}: + - template: java-api-artifacts-package-and-publish-steps-posix.yml parameters: - buildConfig: 'Release' - artifactName: '${{parameters.ArtifactNamePrefix}}-linux-${{parameters.OnnxruntimeArch}}-$(OnnxRuntimeVersion)' - artifactNameNoVersionString: '${{parameters.ArtifactNamePrefix}}-linux-${{parameters.OnnxruntimeArch}}' - libraryName: 'libonnxruntime.so.$(OnnxRuntimeVersion)' + arch: 'linux-${{parameters.OnnxruntimeArch}}' + buildConfig: 'Release' + artifactName: 'onnxruntime-java-linux-${{parameters.OnnxruntimeArch}}' + version: '$(OnnxRuntimeVersion)' + libraryName: 'libonnxruntime.so' + nativeLibraryName: 'libonnxruntime4j_jni.so' + is1ES: true - - ${{ if eq(parameters.PackageNodejs, 'true') }}: - - template: nodejs-artifacts-package-and-publish-steps-posix.yml - parameters: - arch: '${{parameters.OnnxruntimeNodejsBindingArch}}' - os: 'linux' - artifactName: 'drop-onnxruntime-nodejs-linux-${{parameters.OnnxruntimeArch}}' + - template: c-api-artifacts-package-and-publish-steps-posix.yml + parameters: + buildConfig: 'Release' + artifactName: '${{parameters.ArtifactNamePrefix}}-linux-${{parameters.OnnxruntimeArch}}-$(OnnxRuntimeVersion)' + artifactNameNoVersionString: '${{parameters.ArtifactNamePrefix}}-linux-${{parameters.OnnxruntimeArch}}' + libraryName: 'libonnxruntime.so.$(OnnxRuntimeVersion)' - - ${{ if not(eq(parameters.OnnxruntimeNodejsBindingArch, 'arm64')) }}: - - template: component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' + - ${{ if eq(parameters.PackageNodejs, 'true') }}: + - template: nodejs-artifacts-package-and-publish-steps-posix.yml + parameters: + arch: '${{parameters.OnnxruntimeNodejsBindingArch}}' + os: 'linux' + artifactName: 'drop-onnxruntime-nodejs-linux-${{parameters.OnnxruntimeArch}}' diff --git a/tools/ci_build/github/azure-pipelines/templates/clean-agent-build-directory-step.yml b/tools/ci_build/github/azure-pipelines/templates/clean-agent-build-directory-step.yml index 8d6a097ae6dcb..e0a13540351a4 100644 --- a/tools/ci_build/github/azure-pipelines/templates/clean-agent-build-directory-step.yml +++ b/tools/ci_build/github/azure-pipelines/templates/clean-agent-build-directory-step.yml @@ -9,9 +9,6 @@ steps: testRunTitle: 'Unit Test Run' condition: succeededOrFailed() -- template: component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' - script: | diff --git a/tools/ci_build/github/azure-pipelines/templates/common-variables.yml b/tools/ci_build/github/azure-pipelines/templates/common-variables.yml index eb22d003c462e..39a958e848784 100644 --- a/tools/ci_build/github/azure-pipelines/templates/common-variables.yml +++ b/tools/ci_build/github/azure-pipelines/templates/common-variables.yml @@ -1,5 +1,5 @@ variables: - common_trt_version: '10.8.0.43' + common_trt_version: '10.9.0.34' # As for Debian installation, replace '-1.' by '-1+' when assigning trt version below linux_trt_version_cuda11: ${{ variables.common_trt_version }}-1.cuda11.8 linux_trt_version_cuda12: ${{ variables.common_trt_version }}-1.cuda12.8 diff --git a/tools/ci_build/github/azure-pipelines/templates/compliance.yml b/tools/ci_build/github/azure-pipelines/templates/compliance.yml deleted file mode 100644 index cc451425be42a..0000000000000 --- a/tools/ci_build/github/azure-pipelines/templates/compliance.yml +++ /dev/null @@ -1,36 +0,0 @@ -parameters: -- name: msbuildPlatform - displayName: msbuildPlatform - type: string - default: x64 - -steps: -- task: CredScan@2 - displayName: 'Run CredScan' - inputs: - toolMajorVersion: V2 - debugMode: false - continueOnError: true - -- task: BinSkim@4 - displayName: 'Run BinSkim' - inputs: - AnalyzeTargetGlob: '+:file|$(Build.ArtifactStagingDirectory)\**\*.dll;-:file|$(Build.ArtifactStagingDirectory)\**\DirectML.dll' - continueOnError: true - -- task: SdtReport@2 - displayName: 'Create Security Analysis Report' - inputs: - SDLNativeRules: true - -- task: PublishSecurityAnalysisLogs@3 - displayName: 'Publish Security Analysis Logs' - continueOnError: true - -- task: TSAUpload@2 - displayName: 'TSA upload' - condition: and (succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')) - inputs: - GdnPublishTsaOnboard: false - GdnPublishTsaConfigFile: '$(Build.sourcesDirectory)\.gdn\.gdntsa' - continueOnError: true diff --git a/tools/ci_build/github/azure-pipelines/templates/component-governance-component-detection-steps.yml b/tools/ci_build/github/azure-pipelines/templates/component-governance-component-detection-steps.yml deleted file mode 100644 index a5351a182b7a2..0000000000000 --- a/tools/ci_build/github/azure-pipelines/templates/component-governance-component-detection-steps.yml +++ /dev/null @@ -1,47 +0,0 @@ -# component detection for component governance checks -parameters: -- name: condition - type: string - default: 'succeeded' # could be 'ci_only', 'always', 'succeeded' - -steps: -- ${{ if eq(variables['System.TeamProject'], 'Lotus') }}: - - powershell: | - Remove-Item $(Build.BinariesDirectory)/* -Recurse -Force - displayName: 'Clean up build directory' - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - continueOnError: true - condition: - or(or(and(eq('${{parameters.condition}}', 'ci_only'), and(succeeded(), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'Scheduled'))), - and(eq('${{parameters.condition}}', 'always'), always())), - and(eq('${{parameters.condition}}', 'succeeded'), succeeded())) - inputs: - # ignore unit tests in emscripten. emscripten unit tests are not used in onnxruntime build - # ignore onnx third_party directory. onnx third_party directory is not responsible for onnxruntime build - # ignore pybind11 third_party directory. pybind11 third_party directory is not responsible for onnxruntime build - # ignore pybind11 tests directory. pybind11 tests directory is not responsible for onnxruntime build - # ignore onnxruntime-extensions directory. onnxruntime-extensions directory is not responsible for onnxruntime build - # ignore react_native e2e node_modules directory. react_native e2e node_modules directory is generated by react_native e2e tests - # ignore js node_modules directory. js node_modules directory is generated by js tests - # ignore onnxruntime-inference-examples directory. onnxruntime-inference-examples directory is used for inference examples, not for onnxruntime package - # ignore BinariesDirectory. BinariesDirectory is used for build output, not for onnxruntime package - ignoreDirectories: - '$(Build.Repository.LocalPath)/cmake/external/emsdk/upstream/emscripten/tests, - $(Build.Repository.LocalPath)/cmake/external/onnx/third_party/benchmark, - $(Build.Repository.LocalPath)/cmake/external/onnx/third_party/pybind11, - $(Build.Repository.LocalPath)/cmake/external/onnx/third_party/pybind11/tests, - $(Build.Repository.LocalPath)/cmake/external/onnxruntime-extensions, - $(Build.Repository.LocalPath)/js/react_native/e2e/node_modules, - $(Build.Repository.LocalPath)/js/node_modules, - $(Build.Repository.LocalPath)/onnxruntime-inference-examples, - $(Build.SourcesDirectory)/cmake/external/emsdk/upstream/emscripten/tests, - $(Build.SourcesDirectory)/cmake/external/onnx/third_party/benchmark, - $(Build.SourcesDirectory)/cmake/external/onnx/third_party/pybind11, - $(Build.SourcesDirectory)/cmake/external/onnx/third_party/pybind11/tests, - $(Build.SourcesDirectory)/cmake/external/onnxruntime-extensions, - $(Build.SourcesDirectory)/js/react_native/e2e/node_modules, - $(Build.SourcesDirectory)/js/node_modules, - $(Build.SourcesDirectory)/onnxruntime-inference-examples, - $(Build.BinariesDirectory)' \ No newline at end of file diff --git a/tools/ci_build/github/azure-pipelines/templates/explicitly-defined-final-tasks.yml b/tools/ci_build/github/azure-pipelines/templates/explicitly-defined-final-tasks.yml index 047445027220a..fa0f5dde4d639 100644 --- a/tools/ci_build/github/azure-pipelines/templates/explicitly-defined-final-tasks.yml +++ b/tools/ci_build/github/azure-pipelines/templates/explicitly-defined-final-tasks.yml @@ -9,9 +9,6 @@ steps: testRunTitle: 'Unit Test Run' condition: succeededOrFailed() -- template: component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' - script: docker system df && docker system prune -a -f && docker system df displayName: Clean docker images diff --git a/tools/ci_build/github/azure-pipelines/templates/final-jar-testing.yml b/tools/ci_build/github/azure-pipelines/templates/final-jar-testing.yml index 8ccba213af04a..5d947b3c34ad7 100644 --- a/tools/ci_build/github/azure-pipelines/templates/final-jar-testing.yml +++ b/tools/ci_build/github/azure-pipelines/templates/final-jar-testing.yml @@ -26,9 +26,17 @@ stages: clean: all ${{ if eq(parameters.OS, 'MacOS') }}: pool: - vmImage: ${{ parameters.PoolName }} - ${{ else }}: - pool: ${{ parameters.PoolName }} + name: 'Azure Pipelines' + image: macOS-14 + os: macOS + ${{ if eq(parameters.OS, 'Linux') }}: + pool: + name: ${{ parameters.PoolName }} + os: linux + ${{ if eq(parameters.OS, 'Windows') }}: + pool: + name: ${{ parameters.PoolName }} + os: windows variables: - name: runCodesignValidationInjection value: false @@ -87,7 +95,5 @@ stages: - ${{ if eq(parameters['OS'], 'MacOS') }}: - template: use-xcode-version.yml - - template: component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' + diff --git a/tools/ci_build/github/azure-pipelines/templates/java-api-artifacts-package-and-publish-steps-posix.yml b/tools/ci_build/github/azure-pipelines/templates/java-api-artifacts-package-and-publish-steps-posix.yml index 6b469c1a2a551..1c4b0ae5f4137 100644 --- a/tools/ci_build/github/azure-pipelines/templates/java-api-artifacts-package-and-publish-steps-posix.yml +++ b/tools/ci_build/github/azure-pipelines/templates/java-api-artifacts-package-and-publish-steps-posix.yml @@ -7,15 +7,22 @@ parameters: libraryName: 'libonnxruntime.so' nativeLibraryName: 'libonnxruntime4j_jni.so' version: '' + is1ES: false steps: - - task: ShellScript@2 - displayName: 'Copy build artifacts for zipping' - inputs: - scriptPath: 'tools/ci_build/github/linux/java_copy_strip_binary.sh' - args: '-r $(Build.BinariesDirectory) -c ${{parameters.buildConfig}} -a ${{parameters.artifactName}} -l ${{parameters.libraryName}} -n ${{parameters.nativeLibraryName}} -v ${{parameters.version}} -h ${{parameters.arch}}' - workingDirectory: '$(Build.BinariesDirectory)/${{parameters.buildConfig}}' +- task: ShellScript@2 + displayName: 'Copy build artifacts for zipping' + inputs: + scriptPath: 'tools/ci_build/github/linux/java_copy_strip_binary.sh' + args: '-r $(Build.BinariesDirectory) -c ${{parameters.buildConfig}} -a ${{parameters.artifactName}} -l ${{parameters.libraryName}} -n ${{parameters.nativeLibraryName}} -v ${{parameters.version}} -h ${{parameters.arch}}' + workingDirectory: '$(Build.BinariesDirectory)/${{parameters.buildConfig}}' - - task: PublishBuildArtifacts@1 - inputs: - pathtoPublish: '$(Build.BinariesDirectory)/${{parameters.artifactName}}' - artifactName: 'drop-${{parameters.artifactName}}' +- ${{ if eq(parameters.is1ES, true) }}: + - task: 1ES.PublishPipelineArtifact@1 + inputs: + targetPath: '$(Build.BinariesDirectory)/${{parameters.artifactName}}' + artifactName: 'drop-${{parameters.artifactName}}' +- ${{ if eq(parameters.is1ES, false) }}: + - task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: '$(Build.BinariesDirectory)/${{parameters.artifactName}}' + artifactName: 'drop-${{parameters.artifactName}}' diff --git a/tools/ci_build/github/azure-pipelines/templates/jobs/download_linux_qnn_sdk.yml b/tools/ci_build/github/azure-pipelines/templates/jobs/download_linux_qnn_sdk.yml index da91080f34623..9ab308c440e21 100644 --- a/tools/ci_build/github/azure-pipelines/templates/jobs/download_linux_qnn_sdk.yml +++ b/tools/ci_build/github/azure-pipelines/templates/jobs/download_linux_qnn_sdk.yml @@ -1,7 +1,7 @@ parameters: - name: QnnSDKVersion type: string - default: '2.31.0.250130' + default: '2.32.0.250228' steps: - script: | diff --git a/tools/ci_build/github/azure-pipelines/templates/jobs/download_win_gpu_library.yml b/tools/ci_build/github/azure-pipelines/templates/jobs/download_win_gpu_library.yml index ba1373fa6e338..674f16d8e9332 100644 --- a/tools/ci_build/github/azure-pipelines/templates/jobs/download_win_gpu_library.yml +++ b/tools/ci_build/github/azure-pipelines/templates/jobs/download_win_gpu_library.yml @@ -13,10 +13,10 @@ parameters: - 12.2 - name: TrtVersion type: string - default: '10.8.0.43' + default: '10.9.0.34' values: - 8.6.1.6 - - 10.8.0.43 + - 10.9.0.34 steps: - ${{ if eq(parameters.DownloadCUDA, true) }}: @@ -42,7 +42,7 @@ steps: - powershell: | Write-Host "##vso[task.setvariable variable=trtCudaVersion;]12.0" displayName: Set trtCudaVersion - - ${{ if and(eq(parameters.CudaVersion, '12.2'), eq(parameters.TrtVersion, '10.8.0.43')) }}: + - ${{ if and(eq(parameters.CudaVersion, '12.2'), eq(parameters.TrtVersion, '10.9.0.34')) }}: - powershell: | Write-Host "##vso[task.setvariable variable=trtCudaVersion;]12.8" displayName: Set trtCudaVersion diff --git a/tools/ci_build/github/azure-pipelines/templates/jobs/download_win_openvino.yml b/tools/ci_build/github/azure-pipelines/templates/jobs/download_win_openvino.yml new file mode 100644 index 0000000000000..f6956b426ddfc --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/templates/jobs/download_win_openvino.yml @@ -0,0 +1,64 @@ +parameters: + - name: OpenVINOVersion + type: string + default: '2025.0.0' + +steps: + - powershell: | + $Url = "https://storage.openvinotoolkit.org/repositories/openvino/packages/2025.0/windows/openvino_toolkit_windows_2025.0.0.17942.1f68be9f594_x86_64.zip" + $OutputPath = "$env:Agent_TempDirectory\openvino.zip" + $ExtractPath = "$env:Agent_TempDirectory\openvino-v$env:OpenVINOVersion" + $TempExtractPath = "$env:Agent_TempDirectory\openvino_temp" + + # Ensure directories exist + if (Test-Path $ExtractPath) { + Remove-Item -Recurse -Force $ExtractPath + } + New-Item -ItemType Directory -Path $ExtractPath | Out-Null + New-Item -ItemType Directory -Path $TempExtractPath | Out-Null + + # Download OpenVINO ZIP + Write-Output "Downloading OpenVINO" + Invoke-WebRequest -Uri $Url -OutFile $OutputPath + + # Extract to temporary directory first + Write-Output "Extracting OpenVINO to a temporary directory" + Expand-Archive -Path $OutputPath -DestinationPath $TempExtractPath -Force + + # Locate the nested subdirectory + $InnerFolder = Get-ChildItem -Path $TempExtractPath -Directory | Select-Object -First 1 + + if ($InnerFolder) { + Write-Output "Moving extracted files to final destination" + Move-Item -Path "$($InnerFolder.FullName)\*" -Destination $ExtractPath -Force + } else { + Write-Error "Extraction failed: No expected subdirectory found in $TempExtractPath." + Write-Error "The archive may not have extracted correctly, or its structure is different than expected." + exit 1 + } + + # Clean up temporary files + Remove-Item -Recurse -Force $TempExtractPath + Remove-Item -Force $OutputPath + + # Confirm success + Write-Output "OpenVINO extracted to $ExtractPath" + displayName: 'Download OpenVINO Toolkit v${{ parameters.OpenVINOVersion }}' + env: + OpenVINOVersion: ${{ parameters.OpenVINOVersion }} + + - powershell: | + echo "##vso[task.setvariable variable=OpenVINORootDir]$(Agent.TempDirectory)\openvino-v${{ parameters.OpenVINOVersion }}" + displayName: 'Set OpenVINORootDir' + + - task: CmdLine@2 + inputs: + script: | + echo $(OpenVINORootDir) + displayName: 'Print OpenVINORootDir after downloading OpenVINO' + + - task: CmdLine@2 + displayName: 'Print contents of OpenVINO Toolkit' + inputs: + script: | + dir $(OpenVINORootDir) diff --git a/tools/ci_build/github/azure-pipelines/templates/jobs/download_win_qnn_sdk.yml b/tools/ci_build/github/azure-pipelines/templates/jobs/download_win_qnn_sdk.yml index 66793592a6be5..62399443dfd35 100644 --- a/tools/ci_build/github/azure-pipelines/templates/jobs/download_win_qnn_sdk.yml +++ b/tools/ci_build/github/azure-pipelines/templates/jobs/download_win_qnn_sdk.yml @@ -1,7 +1,7 @@ parameters: - name: QnnSDKVersion type: string - default: '2.31.0.250130' + default: '2.32.0.250228' steps: - powershell: | diff --git a/tools/ci_build/github/azure-pipelines/templates/jobs/set-winenv.yml b/tools/ci_build/github/azure-pipelines/templates/jobs/set-winenv.yml index 1a0b8d7f867a6..96436883fb8b8 100644 --- a/tools/ci_build/github/azure-pipelines/templates/jobs/set-winenv.yml +++ b/tools/ci_build/github/azure-pipelines/templates/jobs/set-winenv.yml @@ -10,31 +10,31 @@ parameters: - name: PrimaryCUDAVersion type: string default: '12.2' - - name: SecondaryCUDAVersion - type: string - default: '11.8' - - name: win_trt_folder_cuda11 - type: string - default: 'TensorRT-10.8.0.43.Windows10.x86_64.cuda-11.8' +# - name: SecondaryCUDAVersion +# type: string +# default: '11.8' +# - name: win_trt_folder_cuda11 +# type: string +# default: 'TensorRT-10.9.0.34.Windows10.x86_64.cuda-11.8' - name: win_trt_folder_cuda12 type: string - default: 'TensorRT-10.8.0.43.Windows10.x86_64.cuda-12.8' + default: 'TensorRT-10.9.0.34.Windows10.x86_64.cuda-12.8' steps: - ${{ if eq(parameters.DownloadCUDA, 'true') }}: - powershell: | azcopy.exe cp --recursive "https://lotusscus.blob.core.windows.net/models/cuda_sdk/v${{ parameters.PrimaryCUDAVersion }}" $(Agent.TempDirectory) displayName: 'Download Primary CUDA SDK v${{ parameters.PrimaryCUDAVersion }}' - - powershell: | - azcopy.exe cp --recursive "https://lotusscus.blob.core.windows.net/models/cuda_sdk/v${{ parameters.SecondaryCUDAVersion }}" $(Agent.TempDirectory) - displayName: 'Download Secondary CUDA SDK v${{ parameters.SecondaryCUDAVersion }}' +# - powershell: | +# azcopy.exe cp --recursive "https://lotusscus.blob.core.windows.net/models/cuda_sdk/v${{ parameters.SecondaryCUDAVersion }}" $(Agent.TempDirectory) +# displayName: 'Download Secondary CUDA SDK v${{ parameters.SecondaryCUDAVersion }}' - ${{ if eq(parameters.DownloadTRT, 'true') }}: - powershell: | azcopy.exe cp --recursive "https://lotusscus.blob.core.windows.net/models/local/${{ parameters.win_trt_folder_cuda12 }}" $(Agent.TempDirectory) displayName: 'Download ${{ parameters.win_trt_folder_cuda12 }}' - - powershell: | - azcopy.exe cp --recursive "https://lotusscus.blob.core.windows.net/models/local/${{ parameters.win_trt_folder_cuda11 }}" $(Agent.TempDirectory) - displayName: 'Download ${{ parameters.win_trt_folder_cuda11 }}' +# - powershell: | +# azcopy.exe cp --recursive "https://lotusscus.blob.core.windows.net/models/local/${{ parameters.win_trt_folder_cuda11 }}" $(Agent.TempDirectory) +# displayName: 'Download ${{ parameters.win_trt_folder_cuda11 }}' - task: BatchScript@1 displayName: 'setup env' diff --git a/tools/ci_build/github/azure-pipelines/templates/linux-cpu-packaging-pipeline.yml b/tools/ci_build/github/azure-pipelines/templates/linux-cpu-packaging-pipeline.yml index 7ac2e3a8addb6..fb1c63e1f8a24 100644 --- a/tools/ci_build/github/azure-pipelines/templates/linux-cpu-packaging-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/templates/linux-cpu-packaging-pipeline.yml @@ -34,7 +34,7 @@ stages: PoolName: 'onnxruntime-Ubuntu2204-AMD-CPU' ArtifactNamePrefix: ${{ parameters.ArtifactNamePrefix }} PackageJava: ${{ parameters.PackageJava }} - PackageNodeJS: ${{ parameters.PackageNodeJS }} + PackageNodeJS: false - template: c-api-linux-cpu.yml parameters: diff --git a/tools/ci_build/github/azure-pipelines/templates/linux-wasm-ci.yml b/tools/ci_build/github/azure-pipelines/templates/linux-wasm-ci.yml index e3098841adfba..0e60bf8e2e26d 100644 --- a/tools/ci_build/github/azure-pipelines/templates/linux-wasm-ci.yml +++ b/tools/ci_build/github/azure-pipelines/templates/linux-wasm-ci.yml @@ -39,13 +39,19 @@ parameters: type: boolean default: false +- name: is1ES + displayName: 'Is 1ES pipeline' + type: boolean + default: false + jobs: - job: build_WASM pool: name: ${{ parameters.PoolName }} + os: linux variables: buildArch: x64 - CommonBuildArgs: '--parallel --use_vcpkg --use_vcpkg_ms_internal_asset_cache --config ${{ parameters.BuildConfig }} --skip_submodule_sync --build_wasm --enable_wasm_simd --enable_wasm_threads ${{ parameters.ExtraBuildArgs }}' + CommonBuildArgs: '--parallel --config ${{ parameters.BuildConfig }} --skip_submodule_sync --build_wasm --enable_wasm_simd --enable_wasm_threads ${{ parameters.ExtraBuildArgs }}' runCodesignValidationInjection: false TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] ORT_CACHE_DIR: $(Agent.TempDirectory)/ort_ccache @@ -61,15 +67,15 @@ jobs: displayName: 'Get commit SHA' condition: eq('${{ parameters.CommitOverride }}', 'true') - script: | - export __commit__=<$(Pipeline.Workspace)/__commit.txt - git fetch origin +$__commit__:refs/remotes/origin/$__commit__ - git checkout --force $__commit__ + export __commit__=<$(Pipeline.Workspace)/__commit.txt + git fetch origin +$__commit__:refs/remotes/origin/$__commit__ + git checkout --force $__commit__ workingDirectory: '$(Build.SourcesDirectory)' displayName: 'Read commit SHA and checkout' condition: eq('${{ parameters.CommitOverride }}', 'true') - script: | - git submodule sync --recursive - git submodule update --init --recursive + git submodule sync --recursive + git submodule update --init --recursive workingDirectory: '$(Build.SourcesDirectory)' displayName: 'Checkout submodules' - task: UsePythonVersion@0 @@ -79,19 +85,19 @@ jobs: architecture: $(buildArch) - ${{if eq(parameters.WithCache, true)}}: - - script: | - set -ex - cd '$(Build.SourcesDirectory)/cmake/external/emsdk' - ./emsdk install 4.0.3 ccache-git-emscripten-64bit - ./emsdk activate 4.0.3 ccache-git-emscripten-64bit - displayName: 'emsdk install and activate ccache for emscripten' + - script: | + set -ex + cd '$(Build.SourcesDirectory)/cmake/external/emsdk' + ./emsdk install 4.0.4 ccache-git-emscripten-64bit + ./emsdk activate 4.0.4 ccache-git-emscripten-64bit + displayName: 'emsdk install and activate ccache for emscripten' - ${{if eq(parameters.WithCache, false)}}: - - script: | - set -ex - cd '$(Build.SourcesDirectory)/cmake/external/emsdk' - ./emsdk install 4.0.3 - ./emsdk activate 4.0.3 - displayName: 'emsdk install and activate ccache for emscripten' + - script: | + set -ex + cd '$(Build.SourcesDirectory)/cmake/external/emsdk' + ./emsdk install 4.0.4 + ./emsdk activate 4.0.4 + displayName: 'emsdk install and activate ccache for emscripten' - template: build-linux-wasm-step.yml parameters: @@ -119,11 +125,6 @@ jobs: WithCache: ${{ parameters.WithCache }} - ${{ if eq(parameters.BuildWebGPU, true) }}: - # This step only verifies whether the build is successful. - # currently, we uses EMSDK 3.1.59, which is not compatible with Dawn's changes in its Emscripten fork. Closure compiler will not work for WebGPU build. - # Only enables in DEBUG build. - # - # TODO: when upgrading to a newer Emscripten version, we should fix this step. - template: build-linux-wasm-step.yml parameters: Today: $(Today) @@ -132,25 +133,50 @@ jobs: ${{ else }}: AdditionalKey: wasm_inferencing_webgpu_exp | ${{ parameters.BuildConfig }} CacheDir: $(ORT_CACHE_DIR)/wasm_inferencing_webgpu - Arguments: '$(CommonBuildArgs) --build_dir $(Build.BinariesDirectory)/wasm_inferencing_webgpu --use_webgpu --target onnxruntime_webassembly --skip_tests' + Arguments: '$(CommonBuildArgs) --build_dir $(Build.BinariesDirectory)/wasm_inferencing_webgpu --use_webgpu --use_jsep --use_webnn --target onnxruntime_webassembly --skip_tests' DisplayName: 'Build (simd + threads + WebGPU experimental)' WithCache: ${{ parameters.WithCache }} - ${{ if eq(parameters.SkipPublish, false) }}: - script: | - cp $(Build.BinariesDirectory)/wasm_inferencing/${{ parameters.BuildConfig }}/ort-wasm-simd-threaded.wasm $(Build.ArtifactStagingDirectory) - cp $(Build.BinariesDirectory)/wasm_inferencing/${{ parameters.BuildConfig }}/ort-wasm-simd-threaded.mjs $(Build.ArtifactStagingDirectory) + mkdir -p $(Build.ArtifactStagingDirectory)/wasm/ + cp $(Build.BinariesDirectory)/wasm_inferencing/${{ parameters.BuildConfig }}/ort-wasm-simd-threaded.wasm $(Build.ArtifactStagingDirectory)/wasm/ + cp $(Build.BinariesDirectory)/wasm_inferencing/${{ parameters.BuildConfig }}/ort-wasm-simd-threaded.mjs $(Build.ArtifactStagingDirectory)/wasm/ if [ -d $(Build.BinariesDirectory)/wasm_inferencing_jsep ]; then - cp $(Build.BinariesDirectory)/wasm_inferencing_jsep/${{ parameters.BuildConfig }}/ort-wasm-simd-threaded.jsep.wasm $(Build.ArtifactStagingDirectory) - cp $(Build.BinariesDirectory)/wasm_inferencing_jsep/${{ parameters.BuildConfig }}/ort-wasm-simd-threaded.jsep.mjs $(Build.ArtifactStagingDirectory) + cp $(Build.BinariesDirectory)/wasm_inferencing_jsep/${{ parameters.BuildConfig }}/ort-wasm-simd-threaded.jsep.wasm $(Build.ArtifactStagingDirectory)/wasm/ + cp $(Build.BinariesDirectory)/wasm_inferencing_jsep/${{ parameters.BuildConfig }}/ort-wasm-simd-threaded.jsep.mjs $(Build.ArtifactStagingDirectory)/wasm/ fi displayName: 'Create Artifacts' - - ${{ if eq(parameters.SkipPublish, false) }}: - - task: PublishPipelineArtifact@0 - displayName: 'Publish Pipeline Artifact' - inputs: - artifactName: '${{ parameters.BuildConfig }}_wasm' - targetPath: '$(Build.ArtifactStagingDirectory)' + - ${{ if eq(parameters.BuildWebGPU, true) }}: + - script: | + mkdir -p $(Build.ArtifactStagingDirectory)/wasm_webgpu/ + cp $(Build.BinariesDirectory)/wasm_inferencing_webgpu/${{ parameters.BuildConfig }}/ort-wasm-simd-threaded.jsep.wasm $(Build.ArtifactStagingDirectory)/wasm_webgpu/ + cp $(Build.BinariesDirectory)/wasm_inferencing_webgpu/${{ parameters.BuildConfig }}/ort-wasm-simd-threaded.jsep.mjs $(Build.ArtifactStagingDirectory)/wasm_webgpu/ + displayName: 'Create Artifacts (WebGPU EP)' + - ${{ if eq(parameters.is1ES, false) }}: + - task: PublishPipelineArtifact@1 + displayName: 'Publish Pipeline Artifact' + inputs: + artifactName: '${{ parameters.BuildConfig }}_wasm' + targetPath: '$(Build.ArtifactStagingDirectory)/wasm' + - ${{ if eq(parameters.BuildWebGPU, true) }}: + - task: PublishPipelineArtifact@1 + displayName: 'Publish Pipeline Artifact (WebGPU EP)' + inputs: + artifactName: '${{ parameters.BuildConfig }}_wasm_webgpu' + targetPath: '$(Build.ArtifactStagingDirectory)/wasm_webgpu' + - ${{ if eq(parameters.is1ES, true) }}: + - task: 1ES.PublishPipelineArtifact@1 + displayName: 'Publish Pipeline Artifact' + inputs: + artifactName: '${{ parameters.BuildConfig }}_wasm' + targetPath: '$(Build.ArtifactStagingDirectory)/wasm' + - ${{ if eq(parameters.BuildWebGPU, true) }}: + - task: 1ES.PublishPipelineArtifact@1 + displayName: 'Publish Pipeline Artifact (WebGPU EP)' + inputs: + artifactName: '${{ parameters.BuildConfig }}_wasm_webgpu' + targetPath: '$(Build.ArtifactStagingDirectory)/wasm_webgpu' - task: PublishTestResults@2 displayName: 'Publish unit test results' inputs: @@ -158,6 +184,3 @@ jobs: searchFolder: '$(Build.BinariesDirectory)' testRunTitle: 'Unit Test Run' condition: and(succeededOrFailed(), eq('${{ parameters.BuildConfig }}', 'Debug')) - - template: component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' diff --git a/tools/ci_build/github/azure-pipelines/templates/mac-cpu-packaging-pipeline.yml b/tools/ci_build/github/azure-pipelines/templates/mac-cpu-packaging-pipeline.yml index ab31e592d7d71..8fcdab437052c 100644 --- a/tools/ci_build/github/azure-pipelines/templates/mac-cpu-packaging-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/templates/mac-cpu-packaging-pipeline.yml @@ -42,99 +42,99 @@ stages: - stage: MacOS_C_API_Packaging_CPU dependsOn: [] jobs: + - template: mac-cpu-packing-jobs.yml + parameters: + MacosArch: 'x86_64' + AllowReleasedOpsetOnly: ${{ parameters.AllowReleasedOpsetOnly }} + AdditionalBuildFlags: ${{ parameters.AdditionalBuildFlags }} + WithCache: ${{ parameters.WithCache }} + + - ${{ if eq(parameters.BuildForAllArchs, true) }}: - template: mac-cpu-packing-jobs.yml parameters: - MacosArch: 'x86_64' + MacosArch: 'arm64' + AllowReleasedOpsetOnly: ${{ parameters.AllowReleasedOpsetOnly }} + AdditionalBuildFlags: ${{ parameters.AdditionalBuildFlags }} + WithCache: ${{ parameters.WithCache }} + - template: mac-cpu-packing-jobs.yml + parameters: + MacosArch: 'universal2' AllowReleasedOpsetOnly: ${{ parameters.AllowReleasedOpsetOnly }} AdditionalBuildFlags: ${{ parameters.AdditionalBuildFlags }} WithCache: ${{ parameters.WithCache }} - - - ${{ if eq(parameters.BuildForAllArchs, true) }}: - - template: mac-cpu-packing-jobs.yml - parameters: - MacosArch: 'arm64' - AllowReleasedOpsetOnly: ${{ parameters.AllowReleasedOpsetOnly }} - AdditionalBuildFlags: ${{ parameters.AdditionalBuildFlags }} - WithCache: ${{ parameters.WithCache }} - - template: mac-cpu-packing-jobs.yml - parameters: - MacosArch: 'universal2' - AllowReleasedOpsetOnly: ${{ parameters.AllowReleasedOpsetOnly }} - AdditionalBuildFlags: ${{ parameters.AdditionalBuildFlags }} - WithCache: ${{ parameters.WithCache }} - stage: MacOS_C_API_Package_Publish dependsOn: MacOS_C_API_Packaging_CPU jobs: - - job: MacOS_C_API_Package_Publish - pool: - vmImage: 'macOS-13' - steps: - - checkout: none + - job: MacOS_C_API_Package_Publish + pool: + name: 'Azure Pipelines' + image: 'macOS-14' + os: 'macOS' + steps: + - checkout: none + - template: flex-downloadPipelineArtifact.yml + parameters: + StepName: 'Download Pipeline onnxruntime-osx-x86_64' + ArtifactName: 'onnxruntime-osx-x86_64' + TargetPath: '$(Build.ArtifactStagingDirectory)' + SpecificArtifact: ${{ parameters.SpecificArtifact }} + BuildId: ${{ parameters.BuildId }} + + - ${{ if eq(parameters.BuildForAllArchs, true) }}: + - template: flex-downloadPipelineArtifact.yml + parameters: + StepName: 'Download Pipeline onnxruntime-osx-arm64' + ArtifactName: 'onnxruntime-osx-arm64' + TargetPath: '$(Build.ArtifactStagingDirectory)' + SpecificArtifact: ${{ parameters.SpecificArtifact }} + BuildId: ${{ parameters.BuildId }} - template: flex-downloadPipelineArtifact.yml parameters: - StepName: 'Download Pipeline onnxruntime-osx-x86_64' - ArtifactName: 'onnxruntime-osx-x86_64' + StepName: 'Download Pipeline onnxruntime-osx-universal2' + ArtifactName: 'onnxruntime-osx-universal2' TargetPath: '$(Build.ArtifactStagingDirectory)' SpecificArtifact: ${{ parameters.SpecificArtifact }} BuildId: ${{ parameters.BuildId }} - - ${{ if eq(parameters.BuildForAllArchs, true) }}: - - template: flex-downloadPipelineArtifact.yml - parameters: - StepName: 'Download Pipeline onnxruntime-osx-arm64' - ArtifactName: 'onnxruntime-osx-arm64' - TargetPath: '$(Build.ArtifactStagingDirectory)' - SpecificArtifact: ${{ parameters.SpecificArtifact }} - BuildId: ${{ parameters.BuildId }} - - template: flex-downloadPipelineArtifact.yml - parameters: - StepName: 'Download Pipeline onnxruntime-osx-universal2' - ArtifactName: 'onnxruntime-osx-universal2' - TargetPath: '$(Build.ArtifactStagingDirectory)' - SpecificArtifact: ${{ parameters.SpecificArtifact }} - BuildId: ${{ parameters.BuildId }} + - ${{ if eq(parameters.DoESRP, true)}}: + - script: | + pushd '$(Build.ArtifactStagingDirectory)' + find . '*.tgz' -exec tar -zxvf {} \; + rm -f *.tgz; + find . -type d -name 'onnxruntime-osx-*' -exec zip -FSr --symlinks {}.zip {} \; + find . -type d -name 'onnxruntime-osx-*' -exec rm -rf {} \; + ls -l + popd + displayName: tgz to zip + - template: mac-esrp-dylib.yml + parameters: + FolderPath: '$(Build.ArtifactStagingDirectory)' + DisplayName: 'ESRP - Sign Mac' + DoEsrp: true + Pattern: '*.zip' + - script: | + pushd '$(Build.ArtifactStagingDirectory)' + find . '*.zip' -exec unzip {} \; + rm -f *.zip; + find . -type d -name 'onnxruntime-osx-*' -exec tar -czf {}.tgz {} \; + find . -type d -name 'onnxruntime-osx-*' -exec rm -rf {} \; + ls -l + popd + displayName: zip to tgz + - bash: | + set -ex + mkdir -p $(Agent.TempDirectory)/macpackage + find $(Build.ArtifactStagingDirectory) -name "*.tgz" -exec tar -zxvf {} -C $(Agent.TempDirectory)/macpackage \; + find $(Agent.TempDirectory)/macpackage -name "*.dylib" -exec codesign -dvvv {} \; + find $(Agent.TempDirectory)/macpackage -name "*.dylib" -exec ls -l {} \; + rm -rf $(Agent.TempDirectory)/macpackage + displayName: 'Verify code signing' - - ${{ if eq(parameters.DoESRP, true)}}: - - script: | - pushd '$(Build.ArtifactStagingDirectory)' - find . '*.tgz' -exec tar -zxvf {} \; - rm -f *.tgz; - find . -type d -name 'onnxruntime-osx-*' -exec zip -FSr --symlinks {}.zip {} \; - find . -type d -name 'onnxruntime-osx-*' -exec rm -rf {} \; - ls -l - popd - displayName: tgz to zip - - template: mac-esrp-dylib.yml - parameters: - FolderPath: '$(Build.ArtifactStagingDirectory)' - DisplayName: 'ESRP - Sign Mac' - DoEsrp: true - Pattern: '*.zip' - - script: | - pushd '$(Build.ArtifactStagingDirectory)' - find . '*.zip' -exec unzip {} \; - rm -f *.zip; - find . -type d -name 'onnxruntime-osx-*' -exec tar -czf {}.tgz {} \; - find . -type d -name 'onnxruntime-osx-*' -exec rm -rf {} \; - ls -l - popd - displayName: zip to tgz - - bash: | - set -ex - mkdir -p $(Agent.TempDirectory)/macpackage - find $(Build.ArtifactStagingDirectory) -name "*.tgz" -exec tar -zxvf {} -C $(Agent.TempDirectory)/macpackage \; - find $(Agent.TempDirectory)/macpackage -name "*.dylib" -exec codesign -dvvv {} \; - find $(Agent.TempDirectory)/macpackage -name "*.dylib" -exec ls -l {} \; - rm -rf $(Agent.TempDirectory)/macpackage - displayName: 'Verify code signing' + - task: 1ES.PublishPipelineArtifact@1 + inputs: + targetPath: '$(Build.ArtifactStagingDirectory)' + artifactName: 'onnxruntime-osx' + condition: 'succeededOrFailed()' - - task: PublishPipelineArtifact@1 - inputs: - targetPath: '$(Build.ArtifactStagingDirectory)' - artifact: 'onnxruntime-osx' - condition: 'succeededOrFailed()' - - template: component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' diff --git a/tools/ci_build/github/azure-pipelines/templates/mac-cpu-packaging-steps.yml b/tools/ci_build/github/azure-pipelines/templates/mac-cpu-packaging-steps.yml index 5b94b2da8a096..9a8264a288582 100644 --- a/tools/ci_build/github/azure-pipelines/templates/mac-cpu-packaging-steps.yml +++ b/tools/ci_build/github/azure-pipelines/templates/mac-cpu-packaging-steps.yml @@ -83,8 +83,10 @@ steps: displayName: 'Copy libcustom_op_library.dylib to ArtifactStagingDirectory' condition: and(succeeded(), eq('${{ parameters.MacosArch }}', 'x86_64')) -- publish: '$(Build.ArtifactStagingDirectory)' - artifact: 'onnxruntime-osx-${{ parameters.MacosArch }}' +- task: 1ES.PublishPipelineArtifact@1 + inputs: + targetPath: '$(Build.ArtifactStagingDirectory)' + artifactName: 'onnxruntime-osx-${{ parameters.MacosArch }}' - ${{ if eq(parameters.BuildJava, true) }}: - template: java-api-artifacts-package-and-publish-steps-posix.yml @@ -95,6 +97,7 @@ steps: version: '$(OnnxRuntimeVersion)' libraryName: 'libonnxruntime.dylib' nativeLibraryName: 'libonnxruntime4j_jni.dylib' + is1ES: true - ${{ if eq(parameters.BuildNodejs, true) }}: - template: nodejs-artifacts-package-and-publish-steps-posix.yml diff --git a/tools/ci_build/github/azure-pipelines/templates/mac-cpu-packing-jobs.yml b/tools/ci_build/github/azure-pipelines/templates/mac-cpu-packing-jobs.yml index 32908753f2909..bcc336e65d6ad 100644 --- a/tools/ci_build/github/azure-pipelines/templates/mac-cpu-packing-jobs.yml +++ b/tools/ci_build/github/azure-pipelines/templates/mac-cpu-packing-jobs.yml @@ -37,7 +37,9 @@ jobs: PROTO_CACHE_DIR: $(Pipeline.Workspace)/ccache_proto ORT_CACHE_DIR: $(Pipeline.Workspace)/ccache_ort pool: - vmImage: 'macOS-13' + name: "Azure Pipelines" + image: 'macOS-14' + os: macOS timeoutInMinutes: 300 steps: - checkout: self @@ -75,7 +77,7 @@ jobs: - template: mac-cpu-packaging-steps.yml parameters: MacosArch: ${{ parameters.MacosArch }} - AdditionalBuildFlags: ${{ parameters.AdditionalBuildFlags }} --use_coreml --use_webgpu --cmake_extra_defines CMAKE_OSX_ARCHITECTURES="arm64;x86_64" + AdditionalBuildFlags: ${{ parameters.AdditionalBuildFlags }} --use_coreml --use_webgpu --no_kleidiai --cmake_extra_defines CMAKE_OSX_ARCHITECTURES="arm64;x86_64" BuildJava: false BuildNodejs: false WithCache: ${{ parameters.WithCache }} diff --git a/tools/ci_build/github/azure-pipelines/templates/nodejs-artifacts-package-and-publish-steps-posix.yml b/tools/ci_build/github/azure-pipelines/templates/nodejs-artifacts-package-and-publish-steps-posix.yml index 3a57982c52b1e..df4d3f95a47c7 100644 --- a/tools/ci_build/github/azure-pipelines/templates/nodejs-artifacts-package-and-publish-steps-posix.yml +++ b/tools/ci_build/github/azure-pipelines/templates/nodejs-artifacts-package-and-publish-steps-posix.yml @@ -10,7 +10,7 @@ parameters: default: '' steps: - - task: PublishPipelineArtifact@1 + - task: 1ES.PublishPipelineArtifact@1 inputs: - targetPath: '$(Build.SourcesDirectory)/js/node/bin/napi-v3/${{ parameters.os }}/${{ parameters.arch }}/onnxruntime_binding.node' + targetPath: '$(Build.SourcesDirectory)/js/node/bin/napi-v3/${{ parameters.os }}/${{ parameters.arch }}' artifactName: '${{parameters.artifactName}}' diff --git a/tools/ci_build/github/azure-pipelines/templates/nodejs-artifacts-package-and-publish-steps-windows.yml b/tools/ci_build/github/azure-pipelines/templates/nodejs-artifacts-package-and-publish-steps-windows.yml index 0bc067034b2fc..5286ae6c49142 100644 --- a/tools/ci_build/github/azure-pipelines/templates/nodejs-artifacts-package-and-publish-steps-windows.yml +++ b/tools/ci_build/github/azure-pipelines/templates/nodejs-artifacts-package-and-publish-steps-windows.yml @@ -22,7 +22,7 @@ steps: DoEsrp: ${{parameters.DoEsrp}} Pattern: '*.node' - - task: PublishPipelineArtifact@1 + - task: 1ES.PublishPipelineArtifact@1 inputs: - targetPath: '$(Build.SourcesDirectory)\js\node\bin\napi-v3\win32\${{ parameters.arch }}\onnxruntime_binding.node' + targetPath: '$(Build.SourcesDirectory)\js\node\bin\napi-v3\win32\${{ parameters.arch }}' artifactName: '${{parameters.artifactName}}' diff --git a/tools/ci_build/github/azure-pipelines/templates/ondevice-training-cpu-packaging-pipeline.yml b/tools/ci_build/github/azure-pipelines/templates/ondevice-training-cpu-packaging-pipeline.yml index 48b033cad1afb..56f0a6aad7dd0 100644 --- a/tools/ci_build/github/azure-pipelines/templates/ondevice-training-cpu-packaging-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/templates/ondevice-training-cpu-packaging-pipeline.yml @@ -297,10 +297,6 @@ stages: msbuildArguments: '-t:Clean -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId=$(OrtPackageId)' workingDirectory: '$(Build.SourcesDirectory)\csharp' - - template: component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' - - template: ../nuget/templates/test_win.yml parameters: diff --git a/tools/ci_build/github/azure-pipelines/templates/publish-nuget-steps.yml b/tools/ci_build/github/azure-pipelines/templates/publish-nuget-steps.yml index 6671d3870dd67..2f7f3989e6055 100644 --- a/tools/ci_build/github/azure-pipelines/templates/publish-nuget-steps.yml +++ b/tools/ci_build/github/azure-pipelines/templates/publish-nuget-steps.yml @@ -17,7 +17,8 @@ stages: variables: - name: GDN_CODESIGN_TARGETDIRECTORY value: '$(Agent.TempDirectory)\binfiles' - pool: 'onnxruntime-Win-CPU-2022' + pool: + name: 'onnxruntime-Win-CPU-2022' steps: # https://learn.microsoft.com/en-us/azure/devops/pipelines/yaml-schema/resources-pipelines-pipeline?view=azure-pipelines#pipeline-resource-metadata-as-predefined-variables @@ -53,25 +54,25 @@ stages: displayName: 'Post binary sizes to the dashboard database using command line' inputs: script: | - echo changing directory to artifact download path - cd $(Build.BinariesDirectory)/nuget-artifact/final-package - echo processing nupkg - SETLOCAL EnableDelayedExpansion - FOR /R %%i IN (*.nupkg) do ( - set filename=%%~ni - IF NOT "!filename:~25,7!"=="Managed" ( - echo processing %%~ni.nupkg - copy %%~ni.nupkg %%~ni.zip - echo copied to zip - echo listing lib files in the zip - REM use a single .csv file to put the data - echo os,arch,build_config,size > $(Build.BinariesDirectory)\binary_size_data.txt - 7z.exe l -slt %%~ni.zip runtimes\linux-arm64\native\libonnxruntime.so | findstr /R /C:"^Size = [0-9]*" | for /F "tokens=3" %%a in ('more') do if not "%%a" == "" echo linux,aarch64,default,%%a >> $(Build.BinariesDirectory)\binary_size_data.txt - 7z.exe l -slt %%~ni.zip runtimes\osx-x64\native\libonnxruntime.dylib | findstr /R /C:"^Size = [0-9]*" | for /F "tokens=3" %%a in ('more') do if not "%%a" == "" echo osx,x64,default,%%a >> $(Build.BinariesDirectory)\binary_size_data.txt - 7z.exe l -slt %%~ni.zip runtimes\win-x64\native\onnxruntime.dll | findstr /R /C:"^Size = [0-9]*" | for /F "tokens=3" %%a in ('more') do if not "%%a" == "" echo win,x64,default,%%a >> $(Build.BinariesDirectory)\binary_size_data.txt - 7z.exe l -slt %%~ni.zip runtimes\win-x86\native\onnxruntime.dll | findstr /R /C:"^Size = [0-9]*" | for /F "tokens=3" %%a in ('more') do if not "%%a" == "" echo win,x86,default,%%a >> $(Build.BinariesDirectory)\binary_size_data.txt - ) + echo changing directory to artifact download path + cd $(Build.BinariesDirectory)/nuget-artifact/final-package + echo processing nupkg + SETLOCAL EnableDelayedExpansion + FOR /R %%i IN (*.nupkg) do ( + set filename=%%~ni + IF NOT "!filename:~25,7!"=="Managed" ( + echo processing %%~ni.nupkg + copy %%~ni.nupkg %%~ni.zip + echo copied to zip + echo listing lib files in the zip + REM use a single .csv file to put the data + echo os,arch,build_config,size > $(Build.BinariesDirectory)\binary_size_data.txt + 7z.exe l -slt %%~ni.zip runtimes\linux-arm64\native\libonnxruntime.so | findstr /R /C:"^Size = [0-9]*" | for /F "tokens=3" %%a in ('more') do if not "%%a" == "" echo linux,aarch64,default,%%a >> $(Build.BinariesDirectory)\binary_size_data.txt + 7z.exe l -slt %%~ni.zip runtimes\osx-x64\native\libonnxruntime.dylib | findstr /R /C:"^Size = [0-9]*" | for /F "tokens=3" %%a in ('more') do if not "%%a" == "" echo osx,x64,default,%%a >> $(Build.BinariesDirectory)\binary_size_data.txt + 7z.exe l -slt %%~ni.zip runtimes\win-x64\native\onnxruntime.dll | findstr /R /C:"^Size = [0-9]*" | for /F "tokens=3" %%a in ('more') do if not "%%a" == "" echo win,x64,default,%%a >> $(Build.BinariesDirectory)\binary_size_data.txt + 7z.exe l -slt %%~ni.zip runtimes\win-x86\native\onnxruntime.dll | findstr /R /C:"^Size = [0-9]*" | for /F "tokens=3" %%a in ('more') do if not "%%a" == "" echo win,x86,default,%%a >> $(Build.BinariesDirectory)\binary_size_data.txt ) + ) - task: AzureCLI@2 displayName: 'Azure CLI' @@ -123,14 +124,12 @@ stages: GdnBreakPolicyMinSev: Error #TODO: allow choosing different feeds - - task: NuGetCommand@2 + - task: 1ES.PublishNuget@1 displayName: 'Copy Signed Native NuGet Package to ORT-NIGHTLY' inputs: - command: 'push' packagesToPush: '$(Build.BinariesDirectory)/nuget-artifact/final-package/*.nupkg' + packageParentPath: '$(Build.BinariesDirectory)' publishVstsFeed: '2692857e-05ef-43b4-ba9c-ccf1c22c437c/7982ae20-ed19-4a35-a362-a96ac99897b7' allowPackageConflicts: true - - template: component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' + diff --git a/tools/ci_build/github/azure-pipelines/templates/py-linux-qnn.yml b/tools/ci_build/github/azure-pipelines/templates/py-linux-qnn.yml index 347a3145e8c70..f9d651c79d604 100644 --- a/tools/ci_build/github/azure-pipelines/templates/py-linux-qnn.yml +++ b/tools/ci_build/github/azure-pipelines/templates/py-linux-qnn.yml @@ -6,10 +6,10 @@ parameters: type: string default: 'Release' values: - - Debug - - Release - - RelWithDebInfo - - MinSizeRel + - Debug + - Release + - RelWithDebInfo + - MinSizeRel - name: device type: string @@ -26,69 +26,80 @@ parameters: - name: QnnSdk displayName: QNN SDK version type: string - default: 2.31.0.250130 + default: 2.32.0.250228 + +- name: is1ES + displayName: 'Whether the pipeline is running in 1ES' + type: boolean + default: false jobs: - job: Linux_py_qnn_Wheels_x64 timeoutInMinutes: 240 workspace: clean: all - pool: ${{ parameters.machine_pool }} + pool: + name: ${{ parameters.machine_pool }} + os: linux variables: - # The build machine pool doesn't have dotnet, so it can't run CG. - - name: skipComponentGovernanceDetection - value: true - - name: ORT_CACHE_DIR - value: $(Agent.TempDirectory)/ort_ccache - - name: TODAY - value: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] - - name: extra_build_args - ${{ if ne(parameters.extra_build_arg, '') }}: - value: -x ${{ parameters.extra_build_arg }} - ${{ if eq(parameters.extra_build_arg, '') }}: - value: '' + # The build machine pool doesn't have dotnet, so it can't run CG. + - name: skipComponentGovernanceDetection + value: true + - name: ORT_CACHE_DIR + value: $(Agent.TempDirectory)/ort_ccache + - name: TODAY + value: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] + - name: extra_build_args + ${{ if ne(parameters.extra_build_arg, '') }}: + value: -x ${{ parameters.extra_build_arg }} + ${{ if eq(parameters.extra_build_arg, '') }}: + value: '' steps: - - checkout: self - clean: true - submodules: none + - checkout: self + clean: true + submodules: none - - template: jobs/download_linux_qnn_sdk.yml - parameters: - QnnSDKVersion: ${{ parameters.QnnSdk }} + - template: jobs/download_linux_qnn_sdk.yml + parameters: + QnnSDKVersion: ${{ parameters.QnnSdk }} - - template: set-nightly-build-option-variable-step.yml + - template: set-nightly-build-option-variable-step.yml - - template: get-docker-image-steps.yml - parameters: - Dockerfile: tools/ci_build/github/linux/docker/inference/x86_64/python/cpu/Dockerfile - Context: tools/ci_build/github/linux/docker/inference/x86_64/python/cpu - DockerBuildArgs: "--build-arg BUILD_UID=$( id -u )" - Repository: onnxruntimecpubuildpythonx86_64_qnn + - template: get-docker-image-steps.yml + parameters: + Dockerfile: tools/ci_build/github/linux/docker/inference/x86_64/python/cpu/Dockerfile + Context: tools/ci_build/github/linux/docker/inference/x86_64/python/cpu + DockerBuildArgs: "--build-arg BUILD_UID=$( id -u )" + Repository: onnxruntimecpubuildpythonx86_64_qnn - - template: linux-build-step-with-cache.yml - parameters: - WithCache: ${{parameters.with_cache}} - Today: $(TODAY) - AdditionalKey: Linux_py_qnn_Wheels_x64 - CacheDir: $(ORT_CACHE_DIR) - ChangeEveryCommit: true - BuildStep: - - task: Bash@3 - displayName: 'Build Python Wheel' - inputs: - targetType: filePath - filePath: tools/ci_build/github/linux/run_python_dockerbuild.sh - arguments: -i onnxruntimecpubuildpythonx86_64_qnn -d "${{ parameters.device }}" -c ${{ parameters.cmake_build_type }} $(extra_build_args) - env: - ADDITIONAL_DOCKER_PARAMETER: "--volume $(QnnSDKRootDir):/qnn_sdk" + - template: linux-build-step-with-cache.yml + parameters: + WithCache: ${{parameters.with_cache}} + Today: $(TODAY) + AdditionalKey: Linux_py_qnn_Wheels_x64 + CacheDir: $(ORT_CACHE_DIR) + ChangeEveryCommit: true + BuildStep: + - task: Bash@3 + displayName: 'Build Python Wheel' + inputs: + targetType: filePath + filePath: tools/ci_build/github/linux/run_python_dockerbuild.sh + arguments: -i onnxruntimecpubuildpythonx86_64_qnn -d "${{ parameters.device }}" -c ${{ parameters.cmake_build_type }} $(extra_build_args) + env: + ADDITIONAL_DOCKER_PARAMETER: "--volume $(QnnSDKRootDir):/qnn_sdk" + - ${{ if eq(parameters.is1ES, true) }}: + - task: 1ES.PublishPipelineArtifact@1 + displayName: 'Publish Artifact: Linux ONNXRuntime QNN python wheel' + inputs: + targetPath: '$(Build.BinariesDirectory)/dist' + artifactName: onnxruntime-linux-qnn-x64 - - task: PublishBuildArtifacts@1 + - ${{ if eq(parameters.is1ES, false) }}: + - task: PublishPipelineArtifact@1 displayName: 'Publish Artifact: Linux ONNXRuntime QNN python wheel' inputs: - PathtoPublish: '$(Build.BinariesDirectory)/dist' - ArtifactName: onnxruntime-linux-qnn-x64 + targetPath: '$(Build.BinariesDirectory)/dist' + artifactName: onnxruntime-linux-qnn-x64 - - template: component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' diff --git a/tools/ci_build/github/azure-pipelines/templates/py-linux.yml b/tools/ci_build/github/azure-pipelines/templates/py-linux.yml index e591b719ecfa9..313d9c7fd2b1c 100644 --- a/tools/ci_build/github/azure-pipelines/templates/py-linux.yml +++ b/tools/ci_build/github/azure-pipelines/templates/py-linux.yml @@ -9,10 +9,10 @@ parameters: type: string default: 'Release' values: - - Debug - - Release - - RelWithDebInfo - - MinSizeRel + - Debug + - Release + - RelWithDebInfo + - MinSizeRel - name: device type: string @@ -34,76 +34,95 @@ parameters: type: string default: '' +- name: is1ES + displayName: 'Whether the pipeline is running in 1ES' + type: boolean + default: false + jobs: - job: Linux_py_Wheels_${{ parameters.arch }}_${{parameters.ep}} timeoutInMinutes: 240 workspace: clean: all - pool: ${{ parameters.machine_pool }} + pool: + name: ${{ parameters.machine_pool }} + os: 'linux' + ${{ if eq(parameters.arch, 'aarch64') }}: + hostArchitecture: Arm64 variables: - # The build machine pool doesn't have dotnet, so it can't run CG. - - name: skipComponentGovernanceDetection - value: true - - name: ORT_CACHE_DIR - value: $(Agent.TempDirectory)/ort_ccache - - name: TODAY - value: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] - - name: extra_build_args - ${{ if ne(parameters.extra_build_arg, '') }}: - value: '-x ${{ parameters.extra_build_arg }}' - ${{ if eq(parameters.extra_build_arg, '') }}: - value: '' - - name: python_exe_path - ${{ if ne(parameters.python_exe_path, '') }}: - value: '-p ${{ parameters.python_exe_path }}' - ${{ if eq(parameters.python_exe_path, '') }}: - value: '' + # The build machine pool doesn't have dotnet, so it can't run CG. + - name: skipComponentGovernanceDetection + value: true + - name: ORT_CACHE_DIR + value: $(Agent.TempDirectory)/ort_ccache + - name: TODAY + value: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] + - name: extra_build_args + ${{ if ne(parameters.extra_build_arg, '') }}: + value: '-x ${{ parameters.extra_build_arg }}' + ${{ if eq(parameters.extra_build_arg, '') }}: + value: '' + - name: python_exe_path + ${{ if ne(parameters.python_exe_path, '') }}: + value: '-p ${{ parameters.python_exe_path }}' + ${{ if eq(parameters.python_exe_path, '') }}: + value: '' steps: - - checkout: self - clean: true - submodules: none - - - template: set-nightly-build-option-variable-step.yml - - - template: get-docker-image-steps.yml - parameters: - Dockerfile: tools/ci_build/github/linux/docker/inference/${{ parameters.arch }}/python/cpu/Dockerfile - Context: tools/ci_build/github/linux/docker/inference/${{ parameters.arch }}/python/cpu - DockerBuildArgs: "--build-arg BUILD_UID=$( id -u )" - Repository: onnxruntimecpubuildpython${{ parameters.arch }} - - - template: linux-build-step-with-cache.yml - parameters: - WithCache: ${{parameters.with_cache}} - Today: $(TODAY) - AdditionalKey: Linux_py_Wheels_${{ parameters.arch }} - CacheDir: $(ORT_CACHE_DIR) - ChangeEveryCommit: true - BuildStep: - - task: Bash@3 - displayName: 'Build Python Wheel' - inputs: - targetType: filePath - filePath: tools/ci_build/github/linux/run_python_dockerbuild.sh - arguments: -i onnxruntimecpubuildpython${{ parameters.arch }} -d "${{ parameters.device }}" -c ${{ parameters.cmake_build_type }} $(extra_build_args) $(python_exe_path) - ${{ if eq(parameters.with_cache, 'true') }}: - env: - ADDITIONAL_DOCKER_PARAMETER: "--volume $(ORT_CACHE_DIR):/cache -e CCACHE_DIR=/cache -e ORT_BUILD_WITH_CACHE=1" - - - task: PublishBuildArtifacts@1 + - checkout: self + clean: true + submodules: none + + - template: set-nightly-build-option-variable-step.yml + + - template: get-docker-image-steps.yml + parameters: + Dockerfile: tools/ci_build/github/linux/docker/inference/${{ parameters.arch }}/python/cpu/Dockerfile + Context: tools/ci_build/github/linux/docker/inference/${{ parameters.arch }}/python/cpu + DockerBuildArgs: "--build-arg BUILD_UID=$( id -u )" + Repository: onnxruntimecpubuildpython${{ parameters.arch }} + + - template: linux-build-step-with-cache.yml + parameters: + WithCache: ${{parameters.with_cache}} + Today: $(TODAY) + AdditionalKey: Linux_py_Wheels_${{ parameters.arch }} + CacheDir: $(ORT_CACHE_DIR) + ChangeEveryCommit: true + BuildStep: + - task: Bash@3 + displayName: 'Build Python Wheel' + inputs: + targetType: filePath + filePath: tools/ci_build/github/linux/run_python_dockerbuild.sh + arguments: -i onnxruntimecpubuildpython${{ parameters.arch }} -d "${{ parameters.device }}" -c ${{ parameters.cmake_build_type }} $(extra_build_args) $(python_exe_path) + ${{ if eq(parameters.with_cache, 'true') }}: + env: + ADDITIONAL_DOCKER_PARAMETER: "--volume $(ORT_CACHE_DIR):/cache -e CCACHE_DIR=/cache -e ORT_BUILD_WITH_CACHE=1" + + - ${{ if eq(parameters.is1ES, true) }}: + - task: 1ES.PublishPipelineArtifact@1 displayName: 'Publish Artifact: ONNXRuntime python wheel' inputs: - PathtoPublish: '$(Build.BinariesDirectory)/dist' - ArtifactName: onnxruntime-${{ parameters.ep }} - - - task: PublishPipelineArtifact@0 + targetPath: '$(Build.BinariesDirectory)/dist' + artifactName: onnxruntime-${{ parameters.arch }}-${{ parameters.ep }} + - task: 1ES.PublishPipelineArtifact@1 + displayName: 'Publish Test Binaries' + inputs: + artifactName: 'drop-linux-cpu-${{ parameters.arch }}-${{ parameters.ep }}' + targetPath: '$(Build.BinariesDirectory)/${{ parameters.cmake_build_type }}' + - ${{ if eq(parameters.is1ES, false) }}: + - task: PublishPipelineArtifact@1 + displayName: 'Publish Artifact: ONNXRuntime python wheel' + inputs: + targetPath: '$(Build.BinariesDirectory)/dist' + artifactName: onnxruntime-${{ parameters.arch }}-${{ parameters.ep }} + - task: PublishPipelineArtifact@1 displayName: 'Publish Test Binaries' inputs: artifactName: 'drop-linux-cpu-${{ parameters.arch }}-${{ parameters.ep }}' targetPath: '$(Build.BinariesDirectory)/${{ parameters.cmake_build_type }}' - - template: component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' + + diff --git a/tools/ci_build/github/azure-pipelines/templates/py-package-smoking-test.yml b/tools/ci_build/github/azure-pipelines/templates/py-package-smoking-test.yml index 3a3da0f8f5afa..be9707e8f3f65 100644 --- a/tools/ci_build/github/azure-pipelines/templates/py-package-smoking-test.yml +++ b/tools/ci_build/github/azure-pipelines/templates/py-package-smoking-test.yml @@ -9,9 +9,13 @@ parameters: - name: machine_pool type: object -- name: python_arch +- name: ep type: string - default: 'x64' + default: 'cpu' + +- name: arch + type: string + default: 'x86_64' jobs: - job: ${{ parameters.job_name }} @@ -37,10 +41,9 @@ jobs: displayName: 'Use Python' inputs: versionSpec: $(PythonVersion) - architecture: ${{ parameters.python_arch }} - download: build # pipeline resource identifier. - artifact: 'onnxruntime' + artifact: 'onnxruntime-${{ parameters.arch }}-${{ parameters.ep }}' - task: Bash@3 inputs: @@ -51,9 +54,9 @@ jobs: FILE_NAME="${files[0]}" FILE_NAME=$(basename $FILE_NAME) PYTHON_PACKAGE_NAME=$(echo "$FILE_NAME" | cut -f 1 -d '-') - python3 -m pip install --find-links "$(Pipeline.Workspace)/build/onnxruntime" $PYTHON_PACKAGE_NAME + python3 -m pip install --find-links "$(Pipeline.Workspace)/build/onnxruntime-${{ parameters.arch }}-${{ parameters.ep }}" $PYTHON_PACKAGE_NAME python3 -m pip show $PYTHON_PACKAGE_NAME python3 -c "import onnxruntime as ort; print(ort.__version__)" - workingDirectory: $(Pipeline.Workspace)/build/onnxruntime + workingDirectory: $(Pipeline.Workspace)/build/onnxruntime-${{ parameters.arch }}-${{ parameters.ep }} displayName: Test Package Installation diff --git a/tools/ci_build/github/azure-pipelines/templates/py-packaging-linux-test-cpu.yml b/tools/ci_build/github/azure-pipelines/templates/py-packaging-linux-test-cpu.yml index c475feaef0018..eef97341b8d53 100644 --- a/tools/ci_build/github/azure-pipelines/templates/py-packaging-linux-test-cpu.yml +++ b/tools/ci_build/github/azure-pipelines/templates/py-packaging-linux-test-cpu.yml @@ -19,10 +19,10 @@ parameters: type: string default: 'Release' values: - - Debug - - Release - - RelWithDebInfo - - MinSizeRel + - Debug + - Release + - RelWithDebInfo + - MinSizeRel - name: timeout type: number @@ -50,29 +50,31 @@ jobs: artifact: 'drop-linux-cpu-${{ parameters.arch }}-${{parameters.ep}}' - download: current # pipeline resource identifier. - artifact: 'onnxruntime${{ parameters.python_wheel_suffix }}-${{ parameters.ep }}' + artifact: 'onnxruntime-${{ parameters.arch }}-${{ parameters.ep }}' - bash: | set -e -x mv "$(Pipeline.Workspace)/drop-linux-cpu-${{ parameters.arch }}-${{parameters.ep}}" $(Build.BinariesDirectory)/${{parameters.cmake_build_type}} - mv "$(Pipeline.Workspace)/onnxruntime${{ parameters.python_wheel_suffix }}-${{parameters.ep}}" "$(Build.BinariesDirectory)/whl" + mv "$(Pipeline.Workspace)/onnxruntime-${{ parameters.arch }}-${{ parameters.ep }}" "$(Build.BinariesDirectory)/whl" cp -r "$(Build.BinariesDirectory)/whl" $(Build.BinariesDirectory)/tmp find "$(Build.BinariesDirectory)/tmp" -name '*.whl' -exec bash -c 'unzip -d "${1%.*}" "$1"' _ {} \; + displayName: 'Move the artifacts to the binaries directory' # The private ADO project - ${{ if eq(variables['System.CollectionId'], 'bc038106-a83b-4dab-9dd3-5a41bc58f34c') }}: - download: build # pipeline resource identifier. artifact: 'drop-linux-cpu-${{ parameters.arch }}-${{parameters.ep}}' - download: build # pipeline resource identifier. - artifact: 'onnxruntime${{ parameters.python_wheel_suffix }}-${{ parameters.ep }}' + artifact: 'onnxruntime-${{ parameters.arch }}-${{ parameters.ep }}' - bash: | set -e -x ls $(Pipeline.Workspace)/build mv "$(Pipeline.Workspace)/build/drop-linux-cpu-${{ parameters.arch }}-${{parameters.ep}}" $(Build.BinariesDirectory)/${{parameters.cmake_build_type}} - mv "$(Pipeline.Workspace)/build/onnxruntime${{ parameters.python_wheel_suffix }}-${{parameters.ep}}" "$(Build.BinariesDirectory)/whl" + mv "$(Pipeline.Workspace)/build/onnxruntime-${{ parameters.arch }}-${{ parameters.ep }}" "$(Build.BinariesDirectory)/whl" cp -r "$(Build.BinariesDirectory)/whl" $(Build.BinariesDirectory)/tmp find "$(Build.BinariesDirectory)/tmp" -name '*.whl' -exec bash -c 'unzip -d "${1%.*}" "$1"' _ {} \; + displayName: 'Move the artifacts to the binaries directory' # The BinSkim task uses a dotnet program which doesn't support ARM CPUs yet - ${{ if eq(parameters.arch, 'x86_64') }}: diff --git a/tools/ci_build/github/azure-pipelines/templates/py-packaging-linux-test-cuda.yml b/tools/ci_build/github/azure-pipelines/templates/py-packaging-linux-test-cuda.yml index e7c702042b441..a7760318c1618 100644 --- a/tools/ci_build/github/azure-pipelines/templates/py-packaging-linux-test-cuda.yml +++ b/tools/ci_build/github/azure-pipelines/templates/py-packaging-linux-test-cuda.yml @@ -18,9 +18,8 @@ parameters: - name: cuda_version type: string - default: '11.8' + default: '12.2' values: - - 11.8 - 12.2 # TODO: Ideally it should fetch information from the build that triggers it diff --git a/tools/ci_build/github/azure-pipelines/templates/py-win-arm64-qnn.yml b/tools/ci_build/github/azure-pipelines/templates/py-win-arm64-qnn.yml index 4c9d0dccaf48d..f5c597ab50af9 100644 --- a/tools/ci_build/github/azure-pipelines/templates/py-win-arm64-qnn.yml +++ b/tools/ci_build/github/azure-pipelines/templates/py-win-arm64-qnn.yml @@ -7,7 +7,7 @@ parameters: - name: QNN_SDK displayName: QNN SDK Version type: string - default: 2.31.0.250130 + default: 2.32.0.250228 - name: ENV_SETUP_SCRIPT type: string @@ -19,6 +19,11 @@ parameters: type: string default: '' +- name: is1ES + displayName: 'Whether the pipeline is running in 1ES' + type: boolean + default: false + jobs: - job: Win_py_arm64_qnn_Wheels timeoutInMinutes: 210 @@ -26,6 +31,8 @@ jobs: clean: all pool: name: ${{ parameters.MACHINE_POOL }} + os: windows + hostArchitecture: Arm64 strategy: matrix: Python311_arm64: @@ -41,132 +48,137 @@ jobs: GRADLE_OPTS: '-Dorg.gradle.daemon=false' VSGenerator: 'Visual Studio 17 2022' steps: - - checkout: self - clean: true - submodules: recursive - - - template: telemetry-steps.yml - - - script: | - MKDIR $(Agent.ToolsDirectory)\Python\$(PythonVersion)\arm64 - XCOPY /s /y /h /e /c /q "$(LocalPythonDir)\*.*" $(Agent.ToolsDirectory)\Python\$(PythonVersion)\arm64\ - COPY NUL $(Agent.ToolsDirectory)\Python\$(PythonVersion)\arm64.complete - DIR $(Agent.ToolsDirectory)\Python - DIR $(Agent.ToolsDirectory)\Python\$(PythonVersion) - DIR $(Agent.ToolsDirectory)\Python\$(PythonVersion)\arm64 - displayName: Copy python $(PythonVersion) version to agent tools directory - - - task: UsePythonVersion@0 - inputs: - versionSpec: $(PythonVersion) - addToPath: true - architecture: 'arm64' - - - task: PipAuthenticate@1 - displayName: 'Pip Authenticate' - inputs: - artifactFeeds: 'Lotus' - - - task: onebranch.pipeline.tsaoptions@1 - displayName: 'OneBranch TSAOptions' - inputs: - tsaConfigFilePath: '$(Build.SourcesDirectory)\.config\tsaoptions.json' - appendSourceBranchName: false - - - task: PythonScript@0 - inputs: - scriptSource: inline - script: | - import subprocess - subprocess.call(['pip', 'install', '-q', 'setuptools', 'wheel']) - workingDirectory: '$(Build.BinariesDirectory)' - displayName: 'Install python modules' - - - template: set-nightly-build-option-variable-step.yml - - - template: jobs/download_win_qnn_sdk.yml - parameters: - QnnSDKVersion: ${{ parameters.QNN_SDK }} - - - task: PythonScript@0 - displayName: 'Generate cmake config' - inputs: - scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py' - arguments: > - --config RelWithDebInfo - --build_dir $(Build.BinariesDirectory) - --skip_submodule_sync - --cmake_generator "$(VSGenerator)" - --build_shared_lib - --use_qnn - --qnn_home $(QnnSDKRootDir) - --enable_pybind - --parallel --use_vcpkg --use_vcpkg_ms_internal_asset_cache --update - $(TelemetryOption) ${{ parameters.BUILD_PY_PARAMETERS }} - workingDirectory: '$(Build.BinariesDirectory)' - - - task: VSBuild@1 - displayName: 'Build' - inputs: - solution: '$(Build.BinariesDirectory)\RelWithDebInfo\onnxruntime.sln' - platform: 'arm64' - configuration: RelWithDebInfo - msbuildArchitecture: 'arm64' - maximumCpuCount: true - logProjectEvents: true - workingFolder: '$(Build.BinariesDirectory)\RelWithDebInfo' - createLogFile: true - - # Esrp signing - - template: win-esrp-dll.yml - parameters: - FolderPath: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\onnxruntime\capi' - DisplayName: 'ESRP - Sign Native dlls' - DoEsrp: true - Pattern: '*.pyd' - - - task: PythonScript@0 - displayName: 'Build wheel' - inputs: - scriptPath: '$(Build.SourcesDirectory)\setup.py' - arguments: 'bdist_wheel $(NightlyBuildOption) --wheel_name_suffix=qnn' - workingDirectory: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo' - - - task: CopyFiles@2 - displayName: 'Copy Python Wheel to: $(Build.ArtifactStagingDirectory)' - inputs: - SourceFolder: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\dist' - Contents: '*.whl' - TargetFolder: '$(Build.ArtifactStagingDirectory)' - - - task: PublishBuildArtifacts@1 - displayName: 'Publish Artifact: ONNXRuntime python wheel' - inputs: - ArtifactName: onnxruntime_qnn_arm64 - - - script: | - 7z x *.whl - workingDirectory: '$(Build.ArtifactStagingDirectory)' - displayName: 'unzip the package' - - - task: CredScan@3 - displayName: 'Run CredScan' - inputs: - debugMode: false - continueOnError: true - - - task: BinSkim@4 - displayName: 'Run BinSkim' - inputs: - AnalyzeTargetGlob: '+:file|$(Build.ArtifactStagingDirectory)\**\*.dll' - - - task: TSAUpload@2 - displayName: 'TSA upload' - condition: and (succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')) - inputs: - GdnPublishTsaOnboard: false - GdnPublishTsaConfigFile: '$(Build.sourcesDirectory)\.gdn\.gdntsa' - - - template: component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' + - checkout: self + clean: true + submodules: recursive + + - template: telemetry-steps.yml + + - script: | + MKDIR $(Agent.ToolsDirectory)\Python\$(PythonVersion)\arm64 + XCOPY /s /y /h /e /c /q "$(LocalPythonDir)\*.*" $(Agent.ToolsDirectory)\Python\$(PythonVersion)\arm64\ + COPY NUL $(Agent.ToolsDirectory)\Python\$(PythonVersion)\arm64.complete + DIR $(Agent.ToolsDirectory)\Python + DIR $(Agent.ToolsDirectory)\Python\$(PythonVersion) + DIR $(Agent.ToolsDirectory)\Python\$(PythonVersion)\arm64 + displayName: Copy python $(PythonVersion) version to agent tools directory + + - task: UsePythonVersion@0 + inputs: + versionSpec: $(PythonVersion) + addToPath: true + architecture: 'arm64' + + - task: PipAuthenticate@1 + displayName: 'Pip Authenticate' + inputs: + artifactFeeds: 'Lotus' + + - task: onebranch.pipeline.tsaoptions@1 + displayName: 'OneBranch TSAOptions' + inputs: + tsaConfigFilePath: '$(Build.SourcesDirectory)\.config\tsaoptions.json' + appendSourceBranchName: false + + - task: PythonScript@0 + inputs: + scriptSource: inline + script: | + import subprocess + subprocess.call(['pip', 'install', '-q', 'setuptools', 'wheel']) + workingDirectory: '$(Build.BinariesDirectory)' + displayName: 'Install python modules' + + - template: set-nightly-build-option-variable-step.yml + + - template: jobs/download_win_qnn_sdk.yml + parameters: + QnnSDKVersion: ${{ parameters.QNN_SDK }} + + - task: PythonScript@0 + displayName: 'Generate cmake config' + inputs: + scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py' + arguments: > + --config RelWithDebInfo + --build_dir $(Build.BinariesDirectory) + --skip_submodule_sync + --cmake_generator "$(VSGenerator)" + --build_shared_lib + --use_qnn + --qnn_home $(QnnSDKRootDir) + --enable_pybind + --parallel --use_vcpkg --use_vcpkg_ms_internal_asset_cache --update + $(TelemetryOption) ${{ parameters.BUILD_PY_PARAMETERS }} + workingDirectory: '$(Build.BinariesDirectory)' + + - task: VSBuild@1 + displayName: 'Build' + inputs: + solution: '$(Build.BinariesDirectory)\RelWithDebInfo\onnxruntime.sln' + platform: 'arm64' + configuration: RelWithDebInfo + msbuildArchitecture: 'arm64' + maximumCpuCount: true + logProjectEvents: true + workingFolder: '$(Build.BinariesDirectory)\RelWithDebInfo' + createLogFile: true + + # Esrp signing + - template: win-esrp-dll.yml + parameters: + FolderPath: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\onnxruntime\capi' + DisplayName: 'ESRP - Sign Native dlls' + DoEsrp: true + Pattern: '*.pyd' + + - task: PythonScript@0 + displayName: 'Build wheel' + inputs: + scriptPath: '$(Build.SourcesDirectory)\setup.py' + arguments: 'bdist_wheel $(NightlyBuildOption) --wheel_name_suffix=qnn' + workingDirectory: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo' + + - task: CopyFiles@2 + displayName: 'Copy Python Wheel to: $(Build.ArtifactStagingDirectory)' + inputs: + SourceFolder: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\dist' + Contents: '*.whl' + TargetFolder: '$(Build.ArtifactStagingDirectory)' + + - ${{ if eq(parameters.is1ES, true) }}: + - task: 1ES.PublishPipelineArtifact@1 + displayName: 'Publish Artifact: ONNXRuntime python wheel' + inputs: + artifactName: onnxruntime_qnn_arm64_$(PythonVersion) + targetPath: '$(Build.ArtifactStagingDirectory)' + - ${{ if eq(parameters.is1ES, false) }}: + - task: PublishPipelineArtifact@1 + displayName: 'Publish Artifact: ONNXRuntime python wheel' + input: + artifactName: onnxruntime_qnn_arm64_$(PythonVersion) + targetPath: '$(Build.ArtifactStagingDirectory)' + + - script: | + 7z x *.whl + workingDirectory: '$(Build.ArtifactStagingDirectory)' + displayName: 'unzip the package' + + - task: CredScan@3 + displayName: 'Run CredScan' + inputs: + debugMode: false + continueOnError: true + + - task: BinSkim@4 + displayName: 'Run BinSkim' + inputs: + AnalyzeTargetGlob: '+:file|$(Build.ArtifactStagingDirectory)\**\*.dll' + + - task: TSAUpload@2 + displayName: 'TSA upload' + condition: and (succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')) + inputs: + GdnPublishTsaOnboard: false + GdnPublishTsaConfigFile: '$(Build.sourcesDirectory)\.gdn\.gdntsa' + diff --git a/tools/ci_build/github/azure-pipelines/templates/py-win-arm64ec-qnn.yml b/tools/ci_build/github/azure-pipelines/templates/py-win-arm64ec-qnn.yml index ed29f1e67515e..e8665d9d46d41 100644 --- a/tools/ci_build/github/azure-pipelines/templates/py-win-arm64ec-qnn.yml +++ b/tools/ci_build/github/azure-pipelines/templates/py-win-arm64ec-qnn.yml @@ -7,7 +7,7 @@ parameters: - name: QNN_SDK displayName: QNN SDK Version type: string - default: 2.31.0.250130 + default: 2.32.0.250228 - name: ENV_SETUP_SCRIPT type: string @@ -19,6 +19,11 @@ parameters: type: string default: '' +- name: is1ES + displayName: 'Whether the pipeline is running in 1ES' + type: boolean + default: false + jobs: - job: Win_py_x64_qnn_Wheels timeoutInMinutes: 210 @@ -26,6 +31,7 @@ jobs: clean: all pool: name: ${{ parameters.MACHINE_POOL }} + os: windows strategy: matrix: Python310_x64: @@ -40,117 +46,121 @@ jobs: GRADLE_OPTS: '-Dorg.gradle.daemon=false' VSGenerator: 'Visual Studio 17 2022' steps: - - checkout: self - clean: true - submodules: recursive - - - template: telemetry-steps.yml - - - task: UsePythonVersion@0 - inputs: - versionSpec: $(PythonVersion) - addToPath: true - architecture: 'x64' - - - task: PipAuthenticate@1 - displayName: 'Pip Authenticate' - inputs: - artifactFeeds: 'Lotus' - - - task: onebranch.pipeline.tsaoptions@1 - displayName: 'OneBranch TSAOptions' - inputs: - tsaConfigFilePath: '$(Build.SourcesDirectory)\.config\tsaoptions.json' - appendSourceBranchName: fals - - - script: python -m pip install -r $(Build.SourcesDirectory)\tools\ci_build\github\linux\python\requirements.txt - - - - template: set-nightly-build-option-variable-step.yml - - - template: jobs/download_win_qnn_sdk.yml - parameters: - QnnSDKVersion: ${{ parameters.QNN_SDK }} - - - task: PythonScript@0 - displayName: 'Generate cmake config' - inputs: - scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py' - arguments: > - --config RelWithDebInfo - --build_dir $(Build.BinariesDirectory) - --skip_submodule_sync - --cmake_generator "$(VSGenerator)" - --build_shared_lib - --use_qnn - --qnn_home $(QnnSDKRootDir) - --enable_pybind - --parallel --use_vcpkg --use_vcpkg_ms_internal_asset_cache --update --arm64ec - $(TelemetryOption) ${{ parameters.BUILD_PY_PARAMETERS }} - workingDirectory: '$(Build.BinariesDirectory)' - - - task: VSBuild@1 - displayName: 'Build' - inputs: - solution: '$(Build.BinariesDirectory)\RelWithDebInfo\onnxruntime.sln' - platform: 'arm64ec' - configuration: RelWithDebInfo - msbuildArchitecture: 'x64' - maximumCpuCount: true - logProjectEvents: true - workingFolder: '$(Build.BinariesDirectory)\RelWithDebInfo' - createLogFile: true - - # Esrp signing - - template: win-esrp-dll.yml - parameters: - FolderPath: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\onnxruntime\capi' - DisplayName: 'ESRP - Sign Native dlls' - DoEsrp: true - Pattern: '*.pyd' - - - task: PythonScript@0 - displayName: 'Build wheel' - inputs: - scriptPath: '$(Build.SourcesDirectory)\setup.py' - arguments: 'bdist_wheel $(NightlyBuildOption) --wheel_name_suffix=qnn' - workingDirectory: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo' - - - task: CopyFiles@2 - displayName: 'Copy Python Wheel to: $(Build.ArtifactStagingDirectory)' - inputs: - SourceFolder: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\dist' - Contents: '*.whl' - TargetFolder: '$(Build.ArtifactStagingDirectory)' - - - task: PublishBuildArtifacts@1 - displayName: 'Publish Artifact: ONNXRuntime python wheel' - inputs: - ArtifactName: onnxruntime_qnn_arm64ec - - - script: | - 7z x *.whl - workingDirectory: '$(Build.ArtifactStagingDirectory)' - displayName: 'unzip the package' - - - task: CredScan@3 - displayName: 'Run CredScan' - inputs: - debugMode: false - continueOnError: true - - - task: BinSkim@4 - displayName: 'Run BinSkim' - inputs: - AnalyzeTargetGlob: '+:file|$(Build.ArtifactStagingDirectory)\**\*.dll' - - - task: TSAUpload@2 - displayName: 'TSA upload' - condition: and (succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')) - inputs: - GdnPublishTsaOnboard: false - GdnPublishTsaConfigFile: '$(Build.sourcesDirectory)\.gdn\.gdntsa' - - - template: component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' + - checkout: self + clean: true + submodules: recursive + + - template: telemetry-steps.yml + + - task: UsePythonVersion@0 + inputs: + versionSpec: $(PythonVersion) + addToPath: true + architecture: 'x64' + + - task: PipAuthenticate@1 + displayName: 'Pip Authenticate' + inputs: + artifactFeeds: 'Lotus' + + - task: onebranch.pipeline.tsaoptions@1 + displayName: 'OneBranch TSAOptions' + inputs: + tsaConfigFilePath: '$(Build.SourcesDirectory)\.config\tsaoptions.json' + appendSourceBranchName: fals + + - script: python -m pip install -r $(Build.SourcesDirectory)\tools\ci_build\github\linux\python\requirements.txt + + + - template: set-nightly-build-option-variable-step.yml + + - template: jobs/download_win_qnn_sdk.yml + parameters: + QnnSDKVersion: ${{ parameters.QNN_SDK }} + + - task: PythonScript@0 + displayName: 'Generate cmake config' + inputs: + scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py' + arguments: > + --config RelWithDebInfo + --build_dir $(Build.BinariesDirectory) + --skip_submodule_sync + --cmake_generator "$(VSGenerator)" + --build_shared_lib + --use_qnn + --qnn_home $(QnnSDKRootDir) + --enable_pybind + --parallel --update --arm64ec + $(TelemetryOption) ${{ parameters.BUILD_PY_PARAMETERS }} + workingDirectory: '$(Build.BinariesDirectory)' + + - task: VSBuild@1 + displayName: 'Build' + inputs: + solution: '$(Build.BinariesDirectory)\RelWithDebInfo\onnxruntime.sln' + platform: 'arm64ec' + configuration: RelWithDebInfo + msbuildArchitecture: 'x64' + maximumCpuCount: true + logProjectEvents: true + workingFolder: '$(Build.BinariesDirectory)\RelWithDebInfo' + createLogFile: true + + # Esrp signing + - template: win-esrp-dll.yml + parameters: + FolderPath: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\onnxruntime\capi' + DisplayName: 'ESRP - Sign Native dlls' + DoEsrp: true + Pattern: '*.pyd' + + - task: PythonScript@0 + displayName: 'Build wheel' + inputs: + scriptPath: '$(Build.SourcesDirectory)\setup.py' + arguments: 'bdist_wheel $(NightlyBuildOption) --wheel_name_suffix=qnn' + workingDirectory: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo' + + - task: CopyFiles@2 + displayName: 'Copy Python Wheel to: $(Build.ArtifactStagingDirectory)' + inputs: + SourceFolder: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\dist' + Contents: '*.whl' + TargetFolder: '$(Build.ArtifactStagingDirectory)' + + - ${{ if eq(parameters.is1ES, true) }}: + - task: 1ES.PublishPipelineArtifact@1 + displayName: 'Publish Artifact: ONNXRuntime python wheel' + inputs: + artifactName: onnxruntime_qnn_arm64ec_$(PythonVersion) + targetPath: '$(Build.ArtifactStagingDirectory)' + - ${{ if eq(parameters.is1ES, false) }}: + - task: PublishPipelineArtifact@1 + displayName: 'Publish Artifact: ONNXRuntime python wheel' + inputs: + artifactName: onnxruntime_qnn_arm64ec_$(PythonVersion) + targetPath: '$(Build.ArtifactStagingDirectory)' + - script: | + 7z x *.whl + workingDirectory: '$(Build.ArtifactStagingDirectory)' + displayName: 'unzip the package' + + - task: CredScan@3 + displayName: 'Run CredScan' + inputs: + debugMode: false + continueOnError: true + + - task: BinSkim@4 + displayName: 'Run BinSkim' + inputs: + AnalyzeTargetGlob: '+:file|$(Build.ArtifactStagingDirectory)\**\*.dll' + + - task: TSAUpload@2 + displayName: 'TSA upload' + condition: and (succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')) + inputs: + GdnPublishTsaOnboard: false + GdnPublishTsaConfigFile: '$(Build.sourcesDirectory)\.gdn\.gdntsa' + diff --git a/tools/ci_build/github/azure-pipelines/templates/py-win-x64-qnn.yml b/tools/ci_build/github/azure-pipelines/templates/py-win-x64-qnn.yml index 13069846da342..8f910e8305b76 100644 --- a/tools/ci_build/github/azure-pipelines/templates/py-win-x64-qnn.yml +++ b/tools/ci_build/github/azure-pipelines/templates/py-win-x64-qnn.yml @@ -7,7 +7,7 @@ parameters: - name: QNN_SDK displayName: QNN SDK Version type: string - default: 2.31.0.250130 + default: 2.32.0.250228 - name: ENV_SETUP_SCRIPT type: string @@ -19,6 +19,11 @@ parameters: type: string default: '' +- name: is1ES + displayName: 'Whether the pipeline is running in 1ES' + type: boolean + default: false + jobs: - job: Win_py_x64_qnn_Wheels timeoutInMinutes: 210 @@ -116,10 +121,18 @@ jobs: Contents: '*.whl' TargetFolder: '$(Build.ArtifactStagingDirectory)' - - task: PublishBuildArtifacts@1 - displayName: 'Publish Artifact: ONNXRuntime python wheel' - inputs: - ArtifactName: onnxruntime_qnn_x64 + - ${{ if eq(parameters.is1ES, true) }}: + - task: 1ES.PublishPipelineArtifact@1 + displayName: 'Publish Artifact: ONNXRuntime python wheel' + inputs: + artifactName: onnxruntime_qnn_x64_$(PythonVersion) + targetPath: '$(Build.ArtifactStagingDirectory)' + - ${{ if eq(parameters.is1ES, false) }}: + - task: PublishPipelineArtifact@1 + displayName: 'Publish Artifact: ONNXRuntime python wheel' + inputs: + artifactName: onnxruntime_qnn_x64_$(PythonVersion) + targetPath: '$(Build.ArtifactStagingDirectory)' - script: | 7z x *.whl @@ -142,8 +155,4 @@ jobs: condition: and (succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')) inputs: GdnPublishTsaOnboard: false - GdnPublishTsaConfigFile: '$(Build.sourcesDirectory)\.gdn\.gdntsa' - - - template: component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' + GdnPublishTsaConfigFile: '$(Build.sourcesDirectory)\.gdn\.gdntsa' diff --git a/tools/ci_build/github/azure-pipelines/templates/qnn-ep-win.yml b/tools/ci_build/github/azure-pipelines/templates/qnn-ep-win.yml index a93d6b5ff8419..a799d2eb44a20 100644 --- a/tools/ci_build/github/azure-pipelines/templates/qnn-ep-win.yml +++ b/tools/ci_build/github/azure-pipelines/templates/qnn-ep-win.yml @@ -1,5 +1,5 @@ parameters: - QnnSdk: '2.31.0.250130' + QnnSdk: '2.32.0.250228' build_config: 'RelWithDebInfo' IsReleaseBuild: false DoEsrp: false @@ -10,6 +10,7 @@ parameters: buildPlatform: 'x64' buildArch: 'x64' StageName: 'OnnxRuntime_QNN_Nuget_Win_x64' + PublishArchive: false stages: - stage: ${{ parameters.StageName }} @@ -18,7 +19,8 @@ stages: - job: ${{ parameters.StageName }} timeoutInMinutes: 120 - pool: ${{ parameters.qnn_ep_build_pool_name }} + pool: + name: ${{ parameters.qnn_ep_build_pool_name }} variables: ${{ if eq(parameters.buildArch, 'ARM64') }}: targetArchitecture: 'arm64' @@ -28,134 +30,142 @@ stages: commonBuildArgs: '--update --compile_no_warning_as_error --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --cmake_generator "Visual Studio 17 2022" --config ${{ parameters.build_config }} --parallel --use_binskim_compliant_compile_flags ${{ parameters.buildParameter }} ' steps: - - template: set-version-number-variables-step.yml - - - task: UsePythonVersion@0 - inputs: - versionSpec: '3.12' - addToPath: true - - - template: jobs/download_win_qnn_sdk.yml + - template: set-version-number-variables-step.yml + + - task: UsePythonVersion@0 + inputs: + versionSpec: '3.12' + addToPath: true + + - template: jobs/download_win_qnn_sdk.yml + parameters: + QnnSDKVersion: ${{ parameters.QnnSdk }} + + - task: PythonScript@0 + displayName: 'Generate project' + inputs: + scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py' + arguments: '--use_qnn --qnn_home $(QnnSDKRootDir) $(commonBuildArgs)' + + - task: VSBuild@1 + displayName: 'Build onnxruntime' + inputs: + solution: '$(Build.BinariesDirectory)\${{ parameters.build_config }}\onnxruntime.vcxproj' + platform: ${{ parameters.buildPlatform }} + configuration: ${{ parameters.build_config }} + msbuildArchitecture: ${{ parameters.buildArch }} + maximumCpuCount: true + logProjectEvents: true + workingFolder: '$(Build.BinariesDirectory)\${{ parameters.build_config }}' + createLogFile: true + + - task: VSBuild@1 + displayName: 'Build onnx_test_runner' + inputs: + solution: '$(Build.BinariesDirectory)\${{ parameters.build_config }}\onnx_test_runner.vcxproj' + platform: ${{ parameters.buildPlatform }} + configuration: ${{ parameters.build_config }} + msbuildArchitecture: ${{ parameters.buildArch }} + maximumCpuCount: true + logProjectEvents: true + workingFolder: '$(Build.BinariesDirectory)\${{ parameters.build_config }}' + createLogFile: true + + - task: VSBuild@1 + displayName: 'Build onnxruntime_perf_test' + inputs: + solution: '$(Build.BinariesDirectory)\${{ parameters.build_config }}\onnxruntime_perf_test.vcxproj' + platform: ${{ parameters.buildPlatform }} + configuration: ${{ parameters.build_config }} + msbuildArchitecture: ${{ parameters.buildArch }} + maximumCpuCount: true + logProjectEvents: true + workingFolder: '$(Build.BinariesDirectory)\${{ parameters.build_config }}' + createLogFile: true + + - task: VSBuild@1 + displayName: 'Build onnxruntime_test_all (to copy Qnn libs)' + inputs: + solution: '$(Build.BinariesDirectory)\${{ parameters.build_config }}\onnxruntime_test_all.vcxproj' + platform: ${{ parameters.buildPlatform }} + configuration: ${{ parameters.build_config }} + msbuildArchitecture: ${{ parameters.buildArch }} + maximumCpuCount: true + logProjectEvents: true + workingFolder: '$(Build.BinariesDirectory)\${{ parameters.build_config }}' + createLogFile: true + + - task: CmdLine@2 + displayName: 'Print contents of binaries directory' + inputs: + script: | + dir $(Build.BinariesDirectory)\${{ parameters.build_config }}\${{ parameters.build_config }} + + - template: win-esrp-dll.yml + parameters: + FolderPath: '$(Build.BinariesDirectory)\${{ parameters.build_config }}\${{ parameters.build_config }}' + DisplayName: 'ESRP - Sign dlls' + DoEsrp: ${{ parameters.DoEsrp }} + Pattern: 'onnxruntime*.dll' + + - ${{ if eq(parameters.PublishArchive, true) }}: + - template: c-api-artifacts-package-and-publish-steps-windows.yml parameters: - QnnSDKVersion: ${{ parameters.QnnSdk }} - - - task: PythonScript@0 - displayName: 'Generate project' - inputs: - scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py' - arguments: '--use_qnn --qnn_home $(QnnSDKRootDir) $(commonBuildArgs)' - - - task: VSBuild@1 - displayName: 'Build onnxruntime' - inputs: - solution: '$(Build.BinariesDirectory)\${{ parameters.build_config }}\onnxruntime.vcxproj' - platform: ${{ parameters.buildPlatform }} - configuration: ${{ parameters.build_config }} - msbuildArchitecture: ${{ parameters.buildArch }} - maximumCpuCount: true - logProjectEvents: true - workingFolder: '$(Build.BinariesDirectory)\${{ parameters.build_config }}' - createLogFile: true - - - task: VSBuild@1 - displayName: 'Build onnx_test_runner' - inputs: - solution: '$(Build.BinariesDirectory)\${{ parameters.build_config }}\onnx_test_runner.vcxproj' - platform: ${{ parameters.buildPlatform }} - configuration: ${{ parameters.build_config }} - msbuildArchitecture: ${{ parameters.buildArch }} - maximumCpuCount: true - logProjectEvents: true - workingFolder: '$(Build.BinariesDirectory)\${{ parameters.build_config }}' - createLogFile: true - - - task: VSBuild@1 - displayName: 'Build onnxruntime_perf_test' - inputs: - solution: '$(Build.BinariesDirectory)\${{ parameters.build_config }}\onnxruntime_perf_test.vcxproj' - platform: ${{ parameters.buildPlatform }} - configuration: ${{ parameters.build_config }} - msbuildArchitecture: ${{ parameters.buildArch }} - maximumCpuCount: true - logProjectEvents: true - workingFolder: '$(Build.BinariesDirectory)\${{ parameters.build_config }}' - createLogFile: true - - - task: VSBuild@1 - displayName: 'Build onnxruntime_test_all (to copy Qnn libs)' - inputs: - solution: '$(Build.BinariesDirectory)\${{ parameters.build_config }}\onnxruntime_test_all.vcxproj' - platform: ${{ parameters.buildPlatform }} - configuration: ${{ parameters.build_config }} - msbuildArchitecture: ${{ parameters.buildArch }} - maximumCpuCount: true - logProjectEvents: true - workingFolder: '$(Build.BinariesDirectory)\${{ parameters.build_config }}' - createLogFile: true - - - task: CmdLine@2 - displayName: 'Print contents of binaries directory' - inputs: - script: | - dir $(Build.BinariesDirectory)\${{ parameters.build_config }}\${{ parameters.build_config }} + buildConfig: ${{ parameters.build_config }} + artifactName: 'onnxruntime-win-${{ parameters.buildPlatform }}-qnn' + artifactNameNoVersionString: 'onnxruntime-win-${{ parameters.buildPlatform }}-qnn' + DoEsrp: ${{ parameters.DoEsrp }} + - task: MSBuild@1 + displayName: 'Restore NuGet Packages and create project.assets.json' + inputs: + solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.DesktopOnly.CSharp.sln' + platform: 'Any CPU' + configuration: ${{ parameters.build_config }} + msbuildArguments: '-t:restore -p:OrtPackageId=$(OrtPackageId)' + workingDirectory: '$(Build.SourcesDirectory)\csharp' + + - task: MSBuild@1 + displayName: 'Build C# bindings' + inputs: + solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.DesktopOnly.CSharp.sln' + platform: 'Any CPU' + configuration: ${{ parameters.build_config }} + msbuildArguments: '-p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId=$(OrtPackageId) -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }}' + workingDirectory: '$(Build.SourcesDirectory)\csharp' + + - ${{ if eq(parameters.DoEsrp, true) }}: - template: win-esrp-dll.yml parameters: - FolderPath: '$(Build.BinariesDirectory)\${{ parameters.build_config }}\${{ parameters.build_config }}' - DisplayName: 'ESRP - Sign dlls' + FolderPath: '$(Build.SourcesDirectory)\csharp\src\Microsoft.ML.OnnxRuntime\bin\${{ parameters.build_config }}' + DisplayName: 'ESRP - Sign C# dlls' DoEsrp: ${{ parameters.DoEsrp }} - Pattern: 'onnxruntime*.dll' - - - task: MSBuild@1 - displayName: 'Restore NuGet Packages and create project.assets.json' - inputs: - solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.DesktopOnly.CSharp.sln' - platform: 'Any CPU' - configuration: ${{ parameters.build_config }} - msbuildArguments: '-t:restore -p:OrtPackageId=$(OrtPackageId)' - workingDirectory: '$(Build.SourcesDirectory)\csharp' - - - task: MSBuild@1 - displayName: 'Build C# bindings' - inputs: - solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.DesktopOnly.CSharp.sln' - platform: 'Any CPU' - configuration: ${{ parameters.build_config }} - msbuildArguments: '-p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId=$(OrtPackageId) -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }}' - workingDirectory: '$(Build.SourcesDirectory)\csharp' - - - ${{ if eq(parameters.DoEsrp, true) }}: - - template: win-esrp-dll.yml - parameters: - FolderPath: '$(Build.SourcesDirectory)\csharp\src\Microsoft.ML.OnnxRuntime\bin\${{ parameters.build_config }}' - DisplayName: 'ESRP - Sign C# dlls' - DoEsrp: ${{ parameters.DoEsrp }} - - - task: MSBuild@1 - displayName: 'Build Nuget Packages' - inputs: - solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.proj' - platform: 'Any CPU' - configuration: ${{ parameters.build_config }} - msbuildArguments: '-t:CreatePackage -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId=$(OrtPackageId) -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} -p:TargetArchitecture=$(targetArchitecture)' - workingDirectory: '$(Build.SourcesDirectory)\csharp' - - - task: CopyFiles@2 - displayName: 'Copy native nuget package to: $(Build.ArtifactStagingDirectory)' - inputs: - SourceFolder: '$(Build.BinariesDirectory)\${{ parameters.build_config }}\${{ parameters.build_config }}' - Contents: '*.nupkg' - TargetFolder: '$(Build.ArtifactStagingDirectory)' - - - task: CopyFiles@2 - displayName: 'Copy native nuget symbols package to: $(Build.ArtifactStagingDirectory)' - inputs: - SourceFolder: '$(Build.BinariesDirectory)\${{ parameters.build_config }}\${{ parameters.build_config }}' - Contents: '*.snupkg' - TargetFolder: '$(Build.ArtifactStagingDirectory)' - - - task: PublishPipelineArtifact@0 - displayName: 'Publish Pipeline x64 NuGet Artifact' - inputs: - artifactName: ${{ parameters.ArtifactName }} - targetPath: '$(Build.ArtifactStagingDirectory)' + + - task: MSBuild@1 + displayName: 'Build Nuget Packages' + inputs: + solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.proj' + platform: 'Any CPU' + configuration: ${{ parameters.build_config }} + msbuildArguments: '-t:CreatePackage -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId=$(OrtPackageId) -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} -p:TargetArchitecture=$(targetArchitecture)' + workingDirectory: '$(Build.SourcesDirectory)\csharp' + + - task: CopyFiles@2 + displayName: 'Copy native nuget package to: $(Build.ArtifactStagingDirectory)' + inputs: + SourceFolder: '$(Build.BinariesDirectory)\${{ parameters.build_config }}\${{ parameters.build_config }}' + Contents: '*.nupkg' + TargetFolder: '$(Build.ArtifactStagingDirectory)' + + - task: CopyFiles@2 + displayName: 'Copy native nuget symbols package to: $(Build.ArtifactStagingDirectory)' + inputs: + SourceFolder: '$(Build.BinariesDirectory)\${{ parameters.build_config }}\${{ parameters.build_config }}' + Contents: '*.snupkg' + TargetFolder: '$(Build.ArtifactStagingDirectory)' + + - task: 1ES.PublishPipelineArtifact@1 + displayName: 'Publish Pipeline x64 NuGet Artifact' + inputs: + artifactName: ${{ parameters.ArtifactName }} + targetPath: '$(Build.ArtifactStagingDirectory)' diff --git a/tools/ci_build/github/azure-pipelines/templates/react-native-ci.yml b/tools/ci_build/github/azure-pipelines/templates/react-native-ci.yml index b46fae79899e2..c4de3271f5ca9 100644 --- a/tools/ci_build/github/azure-pipelines/templates/react-native-ci.yml +++ b/tools/ci_build/github/azure-pipelines/templates/react-native-ci.yml @@ -28,6 +28,9 @@ parameters: displayName: Use GPG to sign the jars type: boolean +- name: is1ES + type: boolean + default: false stages: - stage: Build_Android_Packages displayName: Build_Android_Packages @@ -42,6 +45,7 @@ stages: enable_code_sign: '${{parameters.enable_code_sign}}' pool_name: '${{parameters.PoolName}}' packageName: 'onnxruntime-android' + is1ES: '${{parameters.is1ES}}' - stage: ReactNative_CI_Android displayName: ReactNative_CI_Android dependsOn: Build_Android_Packages @@ -51,16 +55,23 @@ stages: PackageName: '${{parameters.PackageName}}' ArtifactName: 'onnxruntime-android-full-aar' NpmPackagingMode: '${{parameters.NpmPackagingMode}}' + is1ES: '${{parameters.is1ES}}' - stage: ReactNative_CI_iOS displayName: ReactNative_CI_iOS dependsOn: '${{parameters.InitialStageDependsOn}}' jobs: - job: ReactNative_CI_iOS - pool: - vmImage: 'macOS-13' + ${{ if eq(parameters.is1ES, false) }}: + pool: + vmImage: 'macOS-14' + ${{ if eq(parameters.is1ES, true) }}: + pool: + name: 'Azure Pipelines' + image: 'macOS-14' + os: 'macOS' - timeoutInMinutes: 90 + timeoutInMinutes: 120 variables: runCodesignValidationInjection: false @@ -107,13 +118,8 @@ stages: inputs: versionSpec: '20.x' - script: - brew install coreutils ninja npm yarn - displayName: Install coreutils, ninja, npm, and yarn - - - script: - yarn global add detox-cli - displayName: Install detox cli tools - + brew install coreutils ninja npm + displayName: Install coreutils, ninja, npm - script: brew tap wix/brew displayName: brew tap wix/brew @@ -122,45 +128,7 @@ stages: brew install applesimutils displayName: Install applesimutils tools required by detox ios - - script: | - npm ci - workingDirectory: '$(Build.SourcesDirectory)/js' - displayName: npm ci js - - - script: | - npm ci - workingDirectory: '$(Build.SourcesDirectory)/js/common' - displayName: npm ci js/common - - - script: | - yarn - workingDirectory: '$(Build.SourcesDirectory)/js/react_native' - displayName: yarn js/react_native - - - task: PowerShell@2 - inputs: - filePath: '$(Build.SourcesDirectory)/tools/ci_build/github/js/pack-npm-packages.ps1' - arguments: '"-dev.$(Get-Date -Format yyyyMMdd)-$(git rev-parse --short HEAD)" $(Build.SourcesDirectory) react_native' - workingDirectory: '$(Build.SourcesDirectory)' - errorActionPreference: stop - env: - ORT_JS_PACK_MODE: e2e - displayName: Pack NPM packages - - - script: | - set -x -e - mv $(Build.SourcesDirectory)/js/common/onnxruntime-common*.tgz onnxruntime-common.tgz - yarn add --no-lockfile file:./onnxruntime-common.tgz - mv $(Build.SourcesDirectory)/js/react_native/onnxruntime-react-native*.tgz onnxruntime-react-native.tgz - yarn add --no-lockfile file:./onnxruntime-react-native.tgz - yarn - workingDirectory: '$(Build.SourcesDirectory)/js/react_native/e2e' - displayName: Bootstrap Android and iOS e2e tests - - - script: | - yarn add --dev jest-junit - workingDirectory: '$(Build.SourcesDirectory)/js/react_native/e2e' - displayName: install jest junit reporter js/react_native/e2e + - template: ../stages/jobs/steps/react-native-bootstrap-steps.yml - script: | ORT_C_LOCAL_POD_PATH=$(Build.BinariesDirectory)/ios-full-pod/onnxruntime-c \ @@ -196,7 +164,7 @@ stages: scheme: 'OnnxruntimeModuleTest' packageApp: false destinationPlatformOption: 'iOS' - destinationSimulators: 'iPhone 14,OS=16.4' + destinationSimulators: 'iPhone 15,OS=17.4' workingDirectory: '$(Build.SourcesDirectory)/js/react_native/ios' xcprettyArgs: '--output build/reports/test-results.xml' publishJUnitResults: true @@ -242,13 +210,20 @@ stages: testRunTitle: 'React Native Detox iOS e2e Test Results' condition: succeededOrFailed() displayName: Publish React Native Detox iOS e2e Test Results - - - task: PublishPipelineArtifact@1 - inputs: - artifact: ios_e2e_test_logs_$(Build.BuildId)_$(Build.BuildNumber)_$(System.JobAttempt) - targetPath: '$(Build.SourcesDirectory)/js/react_native/e2e/artifacts' - condition: succeededOrFailed() - displayName: Publish React Native Detox E2E test logs + - ${{ if eq(parameters.is1ES, true) }}: + - task: 1ES.PublishPipelineArtifact@1 + inputs: + artifactName: 'ios_e2e_test_logs_$(Build.BuildId)_$(Build.BuildNumber)_$(System.JobAttempt)' + targetPath: '$(Build.SourcesDirectory)/js/react_native/e2e/artifacts' + condition: succeededOrFailed() + displayName: Publish React Native Detox E2E test logs + - ${{ if eq(parameters.is1ES, false) }}: + - task: PublishPipelineArtifact@1 + inputs: + artifact: ios_e2e_test_logs_$(Build.BuildId)_$(Build.BuildNumber)_$(System.JobAttempt) + targetPath: '$(Build.SourcesDirectory)/js/react_native/e2e/artifacts' + condition: succeededOrFailed() + displayName: Publish React Native Detox E2E test logs - template: explicitly-defined-final-tasks.yml diff --git a/tools/ci_build/github/azure-pipelines/templates/rocm.yml b/tools/ci_build/github/azure-pipelines/templates/rocm.yml index 1debe9e98eedc..25d58ffe0b29e 100644 --- a/tools/ci_build/github/azure-pipelines/templates/rocm.yml +++ b/tools/ci_build/github/azure-pipelines/templates/rocm.yml @@ -141,8 +141,5 @@ jobs: condition: and(ne(variables['ORT_DISABLE_PYTHON_PACKAGE_LOCAL_VERSION'], 'true'), and(succeeded(), eq(variables['DRY_RUN'], '0'))) displayName: 'Upload Rocm wheel to release repository' - - template: component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' - template: clean-agent-build-directory-step.yml diff --git a/tools/ci_build/github/azure-pipelines/templates/stages/mac-ios-packaging-build-stage.yml b/tools/ci_build/github/azure-pipelines/templates/stages/mac-ios-packaging-build-stage.yml index 90670858c8417..9815e1ac94d24 100644 --- a/tools/ci_build/github/azure-pipelines/templates/stages/mac-ios-packaging-build-stage.yml +++ b/tools/ci_build/github/azure-pipelines/templates/stages/mac-ios-packaging-build-stage.yml @@ -23,8 +23,8 @@ stages: # Note: Keep the Xcode version and iOS simulator version compatible. # Check the table here to see what iOS simulator versions are supported by a particular Xcode version: # https://developer.apple.com/support/xcode/ - xcodeVersion: "14.3.1" - iosSimulatorRuntimeVersion: "16.4" + xcodeVersion: "15.3.0" + iosSimulatorRuntimeVersion: "17.4" ${{ if eq(parameters.packageVariant, 'Full') }}: buildSettingsFile: "tools/ci_build/github/apple/default_full_apple_framework_build_settings.json" cPodName: onnxruntime-c @@ -228,7 +228,3 @@ stages: set -e -x ls -R "$(Build.ArtifactStagingDirectory)" displayName: "List staged artifacts" - - - template: ../component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' diff --git a/tools/ci_build/github/azure-pipelines/templates/use-android-ndk.yml b/tools/ci_build/github/azure-pipelines/templates/use-android-ndk.yml index 50832d1bf1f8b..81a53499bfc98 100644 --- a/tools/ci_build/github/azure-pipelines/templates/use-android-ndk.yml +++ b/tools/ci_build/github/azure-pipelines/templates/use-android-ndk.yml @@ -3,7 +3,7 @@ parameters: - name: AndroidNdkVersion type: string - default: "27.2.12479018" # LTS version + default: "28.0.13004108" # LTS version steps: - bash: | diff --git a/tools/ci_build/github/azure-pipelines/templates/use-xcode-version.yml b/tools/ci_build/github/azure-pipelines/templates/use-xcode-version.yml index 2cf698aefa8bd..3c1bfcd60fedd 100644 --- a/tools/ci_build/github/azure-pipelines/templates/use-xcode-version.yml +++ b/tools/ci_build/github/azure-pipelines/templates/use-xcode-version.yml @@ -3,7 +3,7 @@ parameters: - name: xcodeVersion type: string - default: "14.3.1" + default: "15.3.0" steps: - bash: | diff --git a/tools/ci_build/github/azure-pipelines/templates/web-ci.yml b/tools/ci_build/github/azure-pipelines/templates/web-ci.yml index d2b740b4129f3..e6d86b8802148 100644 --- a/tools/ci_build/github/azure-pipelines/templates/web-ci.yml +++ b/tools/ci_build/github/azure-pipelines/templates/web-ci.yml @@ -57,11 +57,19 @@ parameters: type: boolean default: false +- name: is1ES + displayName: 'Is 1ES pipeline' + type: boolean + default: false + stages: - stage: Precheck_and_extract_commit jobs: - job: Precheck_and_extract_commit - pool: ${{ parameters.PoolName }} + pool: + name: ${{ parameters.PoolName }} + ${{ if or(contains(parameters.PoolName, 'ubuntu'), contains(parameters.PoolName, 'linux')) }}: + os: linux variables: runCodesignValidationInjection: false timeoutInMinutes: 30 @@ -71,8 +79,8 @@ stages: - checkout: self submodules: false - script: | - git submodule sync -- cmake/external/onnx - git submodule update --init -- cmake/external/onnx + git submodule sync -- cmake/external/onnx + git submodule update --init -- cmake/external/onnx workingDirectory: '$(Build.SourcesDirectory)' displayName: 'Checkout submodule onnx' - template: linux-web-init-and-check.yml @@ -83,11 +91,18 @@ stages: script: | echo $(Build.SourceVersion) echo $(Build.SourceVersion) > "$(Build.ArtifactStagingDirectory)"/__commit.txt - - task: PublishPipelineArtifact@0 - displayName: 'Publish __commit.txt' - inputs: - artifactName: '__commit' - targetPath: '$(Build.ArtifactStagingDirectory)' + - ${{ if eq(parameters.is1ES, false) }}: + - task: PublishPipelineArtifact@1 + displayName: 'Publish __commit.txt' + inputs: + artifactName: '__commit' + targetPath: '$(Build.ArtifactStagingDirectory)' + - ${{ if eq(parameters.is1ES, True) }}: + - task: 1ES.PublishPipelineArtifact@1 + displayName: 'Publish __commit.txt' + inputs: + artifactName: '__commit' + targetPath: '$(Build.ArtifactStagingDirectory)' - stage: Build_wasm_Debug dependsOn: Precheck_and_extract_commit @@ -101,6 +116,7 @@ stages: BuildJsep: ${{ parameters.BuildJsep }} BuildWebGPU: ${{ parameters.BuildWebGPU }} WithCache: ${{ parameters.WithCache }} + is1ES: ${{ parameters.is1ES }} - stage: Build_web_Debug dependsOn: Build_wasm_Debug @@ -108,6 +124,7 @@ stages: - template: win-web-ci.yml parameters: CommitOverride: true + is1ES: ${{ parameters.is1ES }} BuildConfig: 'Debug' NpmPackagingMode: ${{ parameters.NpmPackagingMode }} ${{ if eq(parameters.UseWebPoolName, true)}}: @@ -130,8 +147,9 @@ stages: ExtraBuildArgs: '--target onnxruntime_webassembly --skip_tests --enable_wasm_api_exception_catching --disable_rtti ${{ parameters.ExtraBuildArgs }}' PoolName: ${{ parameters.PoolName }} BuildJsep: ${{ parameters.BuildJsep }} - BuildWebGPU: false + BuildWebGPU: ${{ parameters.BuildWebGPU }} WithCache: ${{ parameters.WithCache }} + is1ES: ${{ parameters.is1ES }} - ${{ if eq(parameters.BuildStaticLib, 'true') }}: - stage: Build_wasm_Release_static_library @@ -147,12 +165,14 @@ stages: TimeoutInMinutes: 270 BuildStaticLib: true WithCache: ${{ parameters.WithCache }} + is1ES: ${{ parameters.is1ES }} - stage: Build_web_Release dependsOn: Build_wasm_Release jobs: - template: win-web-ci.yml parameters: + is1ES: ${{ parameters.is1ES }} CommitOverride: true BuildConfig: 'Release' NpmPackagingMode: ${{ parameters.NpmPackagingMode }} diff --git a/tools/ci_build/github/azure-pipelines/templates/win-ci.yml b/tools/ci_build/github/azure-pipelines/templates/win-ci.yml index 600e6d857185f..da869f708418c 100644 --- a/tools/ci_build/github/azure-pipelines/templates/win-ci.yml +++ b/tools/ci_build/github/azure-pipelines/templates/win-ci.yml @@ -161,7 +161,7 @@ stages: displayName: 'Generate cmake config' inputs: scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py' - arguments: '--config RelWithDebInfo --use_binskim_compliant_compile_flags --enable_lto --disable_rtti --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --update --build --use_vcpkg --use_vcpkg_ms_internal_asset_cache --cmake_generator "$(VSGenerator)" --enable_onnx_tests $(TelemetryOption) ${{ parameters.buildparameter }} $(timeoutParameter) $(buildJavaParameter)' + arguments: '--config RelWithDebInfo --use_binskim_compliant_compile_flags --enable_lto --disable_rtti --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --update --build --cmake_generator "$(VSGenerator)" --enable_onnx_tests $(TelemetryOption) ${{ parameters.buildparameter }} $(timeoutParameter) $(buildJavaParameter)' workingDirectory: '$(Build.BinariesDirectory)' @@ -177,10 +177,10 @@ stages: ${{ else }}: buildOnly: false - - task: PublishBuildArtifacts@1 + - task: 1ES.PublishPipelineArtifact@1 displayName: 'Publish Java temp binaries' inputs: - pathtoPublish: '$(Build.BinariesDirectory)\onnxruntime-java-win-${{ parameters.msbuildPlatform }}' + targetPath: '$(Build.BinariesDirectory)\onnxruntime-java-win-${{ parameters.msbuildPlatform }}' artifactName: 'drop-onnxruntime-java-win-${{ parameters.packageName }}${{parameters.artifact_name_suffix}}' # All GPU builds will be tested in the next stage with GPU machine - ${{ if contains(parameters.ort_build_pool_name, 'CPU') }}: @@ -213,11 +213,10 @@ stages: displayName: 'Copy java pad and folder for java test' workingDirectory: '$(Build.BinariesDirectory)' - - task: PublishPipelineArtifact@1 + - task: 1ES.PublishPipelineArtifact@1 inputs: targetPath: '$(Agent.TempDirectory)/RelWithDebInfo' artifactName: 'Windows_Packaging_${{ parameters.stage_name_suffix }}_build_artifacts' - publishLocation: 'pipeline' - script: | dir *.dll @@ -247,38 +246,6 @@ stages: SourceFolder: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo' Contents: 'custom_op_library.dll' TargetFolder: '$(Build.ArtifactStagingDirectory)/testdata' - - - ${{ if eq(parameters['DoCompliance'], 'true') }}: - - task: CredScan@3 - displayName: 'Run CredScan' - inputs: - debugMode: false - continueOnError: true - - - task: BinSkim@4 - displayName: 'Run BinSkim' - inputs: - AnalyzeTargetGlob: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\**\*.dll' - continueOnError: true - - - task: PostAnalysis@2 - inputs: - GdnBreakAllTools: false - GdnBreakGdnToolBinSkim: true - GdnBreakPolicy: M365 - GdnBreakPolicyMinSev: Error - - - task: TSAUpload@2 - displayName: 'TSA upload' - condition: and (succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')) - inputs: - GdnPublishTsaOnboard: false - GdnPublishTsaConfigFile: '$(Build.sourcesDirectory)\.gdn\.gdntsa' - continueOnError: true - - - template: component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' - ${{ if contains(parameters.ort_build_pool_name, 'GPU') }}: - stage: Windows_Packaging_${{ parameters.stage_name_suffix }}_Testing dependsOn: Windows_Packaging_${{ parameters.stage_name_suffix }} diff --git a/tools/ci_build/github/azure-pipelines/templates/win-wasm-ci.yml b/tools/ci_build/github/azure-pipelines/templates/win-wasm-ci.yml index ed1862b78505d..196ea0d7b9ea9 100644 --- a/tools/ci_build/github/azure-pipelines/templates/win-wasm-ci.yml +++ b/tools/ci_build/github/azure-pipelines/templates/win-wasm-ci.yml @@ -154,6 +154,3 @@ jobs: searchFolder: '$(Build.BinariesDirectory)' testRunTitle: 'Unit Test Run' condition: and(succeededOrFailed(), eq('${{ parameters.BuildConfig }}', 'Debug')) - - template: component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' diff --git a/tools/ci_build/github/azure-pipelines/templates/win-web-ci.yml b/tools/ci_build/github/azure-pipelines/templates/win-web-ci.yml index 06e16dcc25046..fecbfc8657894 100644 --- a/tools/ci_build/github/azure-pipelines/templates/win-web-ci.yml +++ b/tools/ci_build/github/azure-pipelines/templates/win-web-ci.yml @@ -24,9 +24,16 @@ parameters: type: boolean default: false +- name: is1ES + displayName: 'Is 1ES pipeline' + type: boolean + default: false + jobs: - job: build_onnxruntime_web - pool: ${{ parameters.PoolName }} + pool: + name: ${{ parameters.PoolName }} + os: windows variables: webgpuCommandlineExtraFlags: '--chromium-flags=--ignore-gpu-blocklist --chromium-flags=--gpu-vendor-id=0x10de' @@ -45,28 +52,28 @@ jobs: displayName: 'Get commit SHA' condition: eq('${{ parameters.CommitOverride }}', 'true') - script: | - set /p __commit__=<$(Pipeline.Workspace)\__commit.txt - git fetch origin +%__commit__%:refs/remotes/origin/%__commit__% - git checkout --force %__commit__% + set /p __commit__=<$(Pipeline.Workspace)\__commit.txt + git fetch origin +%__commit__%:refs/remotes/origin/%__commit__% + git checkout --force %__commit__% workingDirectory: '$(Build.SourcesDirectory)' displayName: 'Read commit SHA and checkout' condition: eq('${{ parameters.CommitOverride }}', 'true') - script: | - echo.$(Build.SourceVersion)>$(Pipeline.Workspace)\__commit.txt + echo.$(Build.SourceVersion)>$(Pipeline.Workspace)\__commit.txt workingDirectory: '$(Build.SourcesDirectory)' displayName: 'Write commit SHA to __commit.txt' condition: ne('${{ parameters.CommitOverride }}', 'true') - script: | - git submodule sync -- cmake\external\onnx - git submodule update --init -- cmake\external\onnx + git submodule sync -- cmake\external\onnx + git submodule update --init -- cmake\external\onnx workingDirectory: '$(Build.SourcesDirectory)' displayName: 'Checkout submodule onnx' - script: | - echo.>>.gitattributes - echo /js/** text=auto eol=lf>>.gitattributes - rd /s /q js - git checkout -- js/** - git checkout -- .gitattributes + echo.>>.gitattributes + echo /js/** text=auto eol=lf>>.gitattributes + rd /s /q js + git checkout -- js/** + git checkout -- .gitattributes workingDirectory: '$(Build.SourcesDirectory)' displayName: 'Testing: force EOL to lf on windows for /js/**' - task: NodeTool@0 @@ -74,55 +81,63 @@ jobs: versionSpec: '20.x' - task: DownloadPipelineArtifact@2 inputs: - patterns: '${{ parameters.BuildConfig }}_*/**/*' - path: $(Pipeline.Workspace)\artifacts + patterns: '${{ parameters.BuildConfig }}_wasm/**/*' + path: $(Pipeline.Workspace)\artifacts_wasm displayName: 'Download WebAssembly artifacts' - task: CopyFiles@2 inputs: - sourceFolder: $(Pipeline.Workspace)\artifacts + sourceFolder: $(Pipeline.Workspace)\artifacts_wasm + contents: | + **\ort-*.wasm + targetFolder: $(Build.SourcesDirectory)\js\web\dist + flattenFolders: true + displayName: 'Binplace dist files (.wasm)' + - task: CopyFiles@2 + inputs: + sourceFolder: $(Pipeline.Workspace)\artifacts_wasm contents: | - **\*.* + **\ort-*.mjs targetFolder: $(Build.SourcesDirectory)\js\web\dist flattenFolders: true - displayName: 'Binplace dist files' + displayName: 'Binplace dist files (.mjs)' - script: | - npm ci + npm ci workingDirectory: '$(Build.SourcesDirectory)\js' displayName: 'npm ci /js/' - script: | - npm ci + npm ci workingDirectory: '$(Build.SourcesDirectory)\js\common' displayName: 'npm ci /js/common/' - script: | - npm test + npm test workingDirectory: '$(Build.SourcesDirectory)\js\common' displayName: 'run onnxruntime-common tests' - script: | - npm ci + npm ci workingDirectory: '$(Build.SourcesDirectory)\js\web' displayName: 'npm ci /js/web/' - script: | - npm run prebuild + npm run prebuild workingDirectory: '$(Build.SourcesDirectory)\js\web' displayName: 'run TypeScript type check in /js/web/' - script: | - npm run lint + npm run lint workingDirectory: '$(Build.SourcesDirectory)\js' displayName: 'run ESLint' - script: | - npm run format + npm run format workingDirectory: '$(Build.SourcesDirectory)\js' displayName: 'Clang-format' - script: | - node -e "a=require('child_process').execSync('git diff --name-only').toString();if(a)throw new Error('Following source files are not formatted: (did you run \"npm run format\"?)\n'+a)" + node -e "a=require('child_process').execSync('git diff --name-only').toString();if(a)throw new Error('Following source files are not formatted: (did you run \"npm run format\"?)\n'+a)" workingDirectory: '$(Build.SourcesDirectory)\js' displayName: 'Check unformatted files' - script: | - npm run build:doc + npm run build:doc workingDirectory: '$(Build.SourcesDirectory)\js\web' displayName: 'Generating documents' - script: | - node -e "a=require('child_process').execSync('git diff --name-only').toString();if(a)throw new Error('Following documents are not up-to-date: (did you run \"npm run build:doc\"?)\n'+a)" + node -e "a=require('child_process').execSync('git diff --name-only').toString();if(a)throw new Error('Following documents are not up-to-date: (did you run \"npm run build:doc\"?)\n'+a)" workingDirectory: '$(Build.SourcesDirectory)\js\web' displayName: 'Check out of dated documents' - task: Cache@2 @@ -142,70 +157,111 @@ jobs: errorActionPreference: stop displayName: 'Pack NPM packages' - script: | - powershell "Get-WmiObject Win32_Process -Filter \"name = 'chrome.exe'\" | Format-List CommandLine" + powershell "Get-WmiObject Win32_Process -Filter \"name = 'chrome.exe'\" | Format-List CommandLine" displayName: 'Check active Chrome processes (before test)' condition: and(succeeded(), eq(variables['Agent.Diagnostic'], 'true')) - script: | - mkdir $(Agent.TempDirectory)\web\test\01 - dir $(Agent.TempDirectory)\web\test\01 - npm test -- -e=chrome -b=webgl,wasm --user-data-dir=$(Agent.TempDirectory)\web\test\01 --chromium-flags=--enable-logging --chromium-flags=--v=1 + mkdir $(Agent.TempDirectory)\web\test\01 + dir $(Agent.TempDirectory)\web\test\01 + npm test -- -e=chrome -b=webgl,wasm --user-data-dir=$(Agent.TempDirectory)\web\test\01 --chromium-flags=--enable-logging --chromium-flags=--v=1 workingDirectory: '$(Build.SourcesDirectory)\js\web' displayName: 'Run ort-web tests (wasm,webgl backend)' condition: and(succeeded(), eq('${{ parameters.RunWebGpuTests }}', 'false')) - script: | - powershell "Get-WmiObject Win32_Process -Filter \"name = 'chrome.exe'\" | Format-List CommandLine" + powershell "Get-WmiObject Win32_Process -Filter \"name = 'chrome.exe'\" | Format-List CommandLine" displayName: 'Check active Chrome processes (before test)' condition: and(succeeded(), eq(variables['Agent.Diagnostic'], 'true')) - script: | - mkdir $(Agent.TempDirectory)\web\test\02 - dir $(Agent.TempDirectory)\web\test\02 - npm test -- -e=chrome -b=webgl,wasm,webgpu $(webgpuCommandlineExtraFlags) --user-data-dir=$(Agent.TempDirectory)\web\test\02 --chromium-flags=--enable-logging --chromium-flags=--v=1 + mkdir $(Agent.TempDirectory)\web\test\02 + dir $(Agent.TempDirectory)\web\test\02 + npm test -- -e=chrome -b=webgl,wasm,webgpu $(webgpuCommandlineExtraFlags) --user-data-dir=$(Agent.TempDirectory)\web\test\02 --chromium-flags=--enable-logging --chromium-flags=--v=1 workingDirectory: '$(Build.SourcesDirectory)\js\web' displayName: 'Run ort-web tests (ALL backends)' condition: and(succeeded(), eq('${{ parameters.RunWebGpuTests }}', 'true')) - script: | - powershell "Get-WmiObject Win32_Process -Filter \"name = 'chrome.exe'\" | Format-List CommandLine" + powershell "Get-WmiObject Win32_Process -Filter \"name = 'chrome.exe'\" | Format-List CommandLine" displayName: 'Check active Chrome processes (before test)' condition: and(succeeded(), eq(variables['Agent.Diagnostic'], 'true')) - script: | - mkdir $(Agent.TempDirectory)\web\test\03 - dir $(Agent.TempDirectory)\web\test\03 - npm test -- suite1 -e=chrome -b=webgpu --io-binding=gpu-tensor $(webgpuCommandlineExtraFlags) --user-data-dir=$(Agent.TempDirectory)\web\test\03 --chromium-flags=--enable-logging --chromium-flags=--v=1 + mkdir $(Agent.TempDirectory)\web\test\03 + dir $(Agent.TempDirectory)\web\test\03 + npm test -- suite1 -e=chrome -b=webgpu --io-binding=gpu-tensor $(webgpuCommandlineExtraFlags) --user-data-dir=$(Agent.TempDirectory)\web\test\03 --chromium-flags=--enable-logging --chromium-flags=--v=1 workingDirectory: '$(Build.SourcesDirectory)\js\web' displayName: 'Run ort-web tests (Suite1, webgpu, IO-binding=gpu-tensor)' condition: and(succeeded(), eq('${{ parameters.RunWebGpuTests }}', 'true')) - script: | - powershell "Get-WmiObject Win32_Process -Filter \"name = 'chrome.exe'\" | Format-List CommandLine" + powershell "Get-WmiObject Win32_Process -Filter \"name = 'chrome.exe'\" | Format-List CommandLine" displayName: 'Check active Chrome processes (before test)' condition: and(succeeded(), eq(variables['Agent.Diagnostic'], 'true')) - script: | - mkdir $(Agent.TempDirectory)\web\test\04 - dir $(Agent.TempDirectory)\web\test\04 - npm test -- suite1 -e=chrome -b=webgpu --io-binding=gpu-location $(webgpuCommandlineExtraFlags) --user-data-dir=$(Agent.TempDirectory)\web\test\04 --chromium-flags=--enable-logging --chromium-flags=--v=1 + mkdir $(Agent.TempDirectory)\web\test\04 + dir $(Agent.TempDirectory)\web\test\04 + npm test -- suite1 -e=chrome -b=webgpu --io-binding=gpu-location $(webgpuCommandlineExtraFlags) --user-data-dir=$(Agent.TempDirectory)\web\test\04 --chromium-flags=--enable-logging --chromium-flags=--v=1 workingDirectory: '$(Build.SourcesDirectory)\js\web' displayName: 'Run ort-web tests (Suite1, webgpu, IO-binding=gpu-location)' condition: and(succeeded(), eq('${{ parameters.RunWebGpuTests }}', 'true')) - script: | - powershell "Get-WmiObject Win32_Process -Filter \"name = 'chrome.exe'\" | Format-List CommandLine" + powershell "Get-WmiObject Win32_Process -Filter \"name = 'chrome.exe'\" | Format-List CommandLine" displayName: 'Check active Chrome processes (before test)' condition: and(succeeded(), eq(variables['Agent.Diagnostic'], 'true')) - script: | - mkdir $(Agent.TempDirectory)\web\test\05 - dir $(Agent.TempDirectory)\web\test\05 - npm test -- --webgl.pack -b=webgl -e=chrome --user-data-dir=$(Agent.TempDirectory)\web\test\05 --chromium-flags=--enable-logging --chromium-flags=--v=1 + mkdir $(Agent.TempDirectory)\web\test\05 + dir $(Agent.TempDirectory)\web\test\05 + npm test -- --webgl.pack -b=webgl -e=chrome --user-data-dir=$(Agent.TempDirectory)\web\test\05 --chromium-flags=--enable-logging --chromium-flags=--v=1 workingDirectory: '$(Build.SourcesDirectory)\js\web' displayName: 'Run ort-web tests - WebGL: packed mode' - script: | - powershell "Get-WmiObject Win32_Process -Filter \"name = 'chrome.exe'\" | Format-List CommandLine" + powershell "Get-WmiObject Win32_Process -Filter \"name = 'chrome.exe'\" | Format-List CommandLine" displayName: 'Check active Chrome processes (before test)' condition: and(succeeded(), eq(variables['Agent.Diagnostic'], 'true')) - script: | - mkdir $(Agent.TempDirectory)\web\test\06 - dir $(Agent.TempDirectory)\web\test\06 - npm test -- --wasm.proxy -b=wasm -e=chrome --user-data-dir=$(Agent.TempDirectory)\web\test\06 --chromium-flags=--enable-logging --chromium-flags=--v=1 + mkdir $(Agent.TempDirectory)\web\test\06 + dir $(Agent.TempDirectory)\web\test\06 + npm test -- --wasm.proxy -b=wasm -e=chrome --user-data-dir=$(Agent.TempDirectory)\web\test\06 --chromium-flags=--enable-logging --chromium-flags=--v=1 workingDirectory: '$(Build.SourcesDirectory)\js\web' displayName: 'Run ort-web tests - WebAssembly: proxy' condition: and(succeeded(), eq('${{ parameters.BuildConfig }}', 'Release')) + + # === Start of experimental WebGPU EP tests === + + - ${{ if eq(parameters.RunWebGpuTests, true) }}: + - task: DownloadPipelineArtifact@2 + inputs: + patterns: '${{ parameters.BuildConfig }}_wasm_webgpu/**/*' + path: $(Pipeline.Workspace)\artifacts_wasm_webgpu + displayName: 'Download WebAssembly artifacts' + - task: CopyFiles@2 + inputs: + sourceFolder: $(Pipeline.Workspace)\artifacts_wasm_webgpu + contents: | + **\ort-*.wasm + targetFolder: $(Build.SourcesDirectory)\js\web\dist + flattenFolders: true + overWrite: true + displayName: 'Binplace dist files (.wasm)' + - task: CopyFiles@2 + inputs: + sourceFolder: $(Pipeline.Workspace)\artifacts_wasm_webgpu + contents: | + **\ort-*.mjs + targetFolder: $(Build.SourcesDirectory)\js\web\dist + flattenFolders: true + overWrite: true + displayName: 'Binplace dist files (.mjs)' + - script: | + powershell "Get-WmiObject Win32_Process -Filter \"name = 'chrome.exe'\" | Format-List CommandLine" + displayName: 'Check active Chrome processes (before test)' + condition: and(succeeded(), eq(variables['Agent.Diagnostic'], 'true')) + - script: | + mkdir $(Agent.TempDirectory)\web\test\07 + dir $(Agent.TempDirectory)\web\test\07 + npm test --webgpu-ep -- -b=webgpu -e=chrome $(webgpuCommandlineExtraFlags) --user-data-dir=$(Agent.TempDirectory)\web\test\07 --chromium-flags=--enable-logging --chromium-flags=--v=1 + workingDirectory: '$(Build.SourcesDirectory)\js\web' + displayName: 'Run ort-web tests - WebGPU EP' + continueOnError: true # we allow WebGPU EP tests to fail for now + + # === End of experimental WebGPU EP tests === + - script: | npm run test:e2e -- --browser=Chrome_default workingDirectory: '$(Build.SourcesDirectory)\js\web' @@ -226,22 +282,28 @@ jobs: targetFolder: $(Build.ArtifactStagingDirectory) displayName: 'Create Artifacts (onnxruntime-web)' condition: and(succeeded(), eq('${{ parameters.BuildConfig }}', 'Release')) - - task: PublishPipelineArtifact@0 - inputs: - artifactName: '${{ parameters.PackageName }}' - targetPath: '$(Build.ArtifactStagingDirectory)' - displayName: 'Publish Pipeline Artifact' - condition: and(succeeded(), eq('${{ parameters.BuildConfig }}', 'Release')) + - ${{ if eq(parameters.is1ES, false) }}: + - task: PublishPipelineArtifact@0 + inputs: + artifactName: '${{ parameters.PackageName }}' + targetPath: '$(Build.ArtifactStagingDirectory)' + displayName: 'Publish Pipeline Artifact' + condition: and(succeeded(), eq('${{ parameters.BuildConfig }}', 'Release')) + - ${{ if eq(parameters.is1ES, true) }}: + - task: 1ES.PublishPipelineArtifact@1 + inputs: + artifactName: '${{ parameters.PackageName }}' + targetPath: '$(Build.ArtifactStagingDirectory)' + displayName: 'Publish Pipeline Artifact' + condition: and(succeeded(), eq('${{ parameters.BuildConfig }}', 'Release')) - script: | - if exist 01 (echo ------------------- BEGIN 01 -------------------&&type 01\chrome_debug.log&&echo ------------------- END 01 ------------------- ) - if exist 02 (echo ------------------- BEGIN 02 -------------------&&type 02\chrome_debug.log&&echo ------------------- END 02 ------------------- ) - if exist 03 (echo ------------------- BEGIN 03 -------------------&&type 03\chrome_debug.log&&echo ------------------- END 03 ------------------- ) - if exist 04 (echo ------------------- BEGIN 04 -------------------&&type 04\chrome_debug.log&&echo ------------------- END 04 ------------------- ) - if exist 05 (echo ------------------- BEGIN 05 -------------------&&type 05\chrome_debug.log&&echo ------------------- END 05 ------------------- ) - if exist 06 (echo ------------------- BEGIN 06 -------------------&&type 06\chrome_debug.log&&echo ------------------- END 06 ------------------- ) + for %%i in (01 02 03 04 05 06 07) do ( + if exist %%i ( + echo ------------------- BEGIN %%i ------------------- + type %%i\chrome_debug.log + echo ------------------- END %%i ------------------- + ) + ) displayName: 'Log Chrome processes (after test)' workingDirectory: '$(Agent.TempDirectory)\web\test' condition: always() - - template: component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' diff --git a/tools/ci_build/github/azure-pipelines/templates/win-web-multi-browsers.yml b/tools/ci_build/github/azure-pipelines/templates/win-web-multi-browsers.yml index e201cc0ffdd5a..00df695889b1d 100644 --- a/tools/ci_build/github/azure-pipelines/templates/win-web-multi-browsers.yml +++ b/tools/ci_build/github/azure-pipelines/templates/win-web-multi-browsers.yml @@ -44,10 +44,18 @@ jobs: inputs: sourceFolder: $(Pipeline.Workspace)\artifacts contents: | - **\*.* + **\ort-*.wasm targetFolder: $(Build.SourcesDirectory)\js\web\dist flattenFolders: true - displayName: 'Binplace dist files' + displayName: 'Binplace dist files (.wasm)' + - task: CopyFiles@2 + inputs: + sourceFolder: $(Pipeline.Workspace)\artifacts + contents: | + **\ort-*.mjs + targetFolder: $(Build.SourcesDirectory)\js\web\dist + flattenFolders: true + displayName: 'Binplace dist files (.mjs)' - script: | npm ci workingDirectory: '$(Build.SourcesDirectory)\js' diff --git a/tools/ci_build/github/azure-pipelines/templates/windowsai-steps.yml b/tools/ci_build/github/azure-pipelines/templates/windowsai-steps.yml index fb3ebdc760a7b..355a575307f0b 100644 --- a/tools/ci_build/github/azure-pipelines/templates/windowsai-steps.yml +++ b/tools/ci_build/github/azure-pipelines/templates/windowsai-steps.yml @@ -89,7 +89,7 @@ jobs: # must call vsdevcmd first to add cmake to PATH - script: | python --version - python "$(Build.SourcesDirectory)\tools\ci_build\build.py" --build_dir $(Build.BinariesDirectory) --parallel --use_binskim_compliant_compile_flags --build_shared_lib --enable_onnx_tests --ms_experimental --use_dml --use_winml --cmake_generator "Visual Studio 17 2022" --update --config RelWithDebInfo --enable_lto --use_telemetry --disable_rtti --enable_wcos --windows_sdk_version "10.0.22621.0" $(BuildFlags) --cmake_extra_defines "CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO=/PROFILE" "CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO=/PROFILE" + python "$(Build.SourcesDirectory)\tools\ci_build\build.py" --build_dir $(Build.BinariesDirectory) --parallel --use_binskim_compliant_compile_flags --build_shared_lib --enable_onnx_tests --ms_experimental --use_dml --use_winml --cmake_generator "Visual Studio 17 2022" --update --config RelWithDebInfo --enable_lto --use_telemetry --disable_rtti --enable_wcos --use_vcpkg --use_vcpkg_ms_internal_asset_cache --windows_sdk_version "10.0.22621.0" $(BuildFlags) --cmake_extra_defines "CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO=/PROFILE" "CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO=/PROFILE" workingDirectory: '$(Build.BinariesDirectory)' displayName: 'Generate cmake config' diff --git a/tools/ci_build/github/azure-pipelines/win-ci-fuzz-testing.yml b/tools/ci_build/github/azure-pipelines/win-ci-fuzz-testing.yml index f02e760130ff4..093b4ee7ec50d 100644 --- a/tools/ci_build/github/azure-pipelines/win-ci-fuzz-testing.yml +++ b/tools/ci_build/github/azure-pipelines/win-ci-fuzz-testing.yml @@ -66,7 +66,3 @@ jobs: script: '$(Build.BinariesDirectory)\$(BuildConfig)\$(BuildConfig)\onnxruntime_security_fuzz.exe /t /f "$(Build.BinariesDirectory)\$(BuildConfig)\$(BuildConfig)\testdata\mnist.onnx" 1 m' workingDirectory: $(Build.BinariesDirectory)\$(BuildConfig)\$(BuildConfig) failOnStderr: false # Optional - - - template: templates/component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' diff --git a/tools/ci_build/github/azure-pipelines/win-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/win-ci-pipeline.yml deleted file mode 100644 index 54c2e51c2a09b..0000000000000 --- a/tools/ci_build/github/azure-pipelines/win-ci-pipeline.yml +++ /dev/null @@ -1,261 +0,0 @@ -##### start trigger Don't edit it manually, Please do edit set-trigger-rules.py #### -### please do rerun set-trigger-rules.py ### -trigger: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -pr: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -#### end trigger #### - -parameters: -- name: RunOnnxRuntimeTests - displayName: Run Tests? - type: boolean - default: true - -stages: -- stage: x64_debug - dependsOn: [] - jobs: - - template: templates/jobs/win-ci-vs-2022-job.yml - parameters: - BuildConfig: 'Debug' - buildArch: x64 - additionalBuildFlags: --build_java --build_nodejs --build_wheel --disable_memleak_checker --msbuild_extra_options IncludeMobileTargets=false --build_nuget --use_vcpkg --use_vcpkg_ms_internal_asset_cache - msbuildPlatform: x64 - isX86: false - job_name_suffix: x64_debug - RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - isTraining: false - ORT_EP_NAME: CPU - GenerateDocumentation: false - WITH_CACHE: false - MachinePool: 'onnxruntime-Win-CPU-2022' - - - job: build_x64_asan - pool: 'onnxruntime-Win-CPU-2022' - timeoutInMinutes: 300 - steps: - - checkout: self - clean: true - submodules: none - - - template: templates/jobs/win-ci-prebuild-steps.yml - parameters: - EnvSetupScript: setup_env.bat - DownloadCUDA: false - BuildArch: x64 - BuildConfig: Debug - MachinePool: 'onnxruntime-Win-CPU-2022' - WithCache: false - Today: $(TODAY) - - - task: PythonScript@0 - displayName: 'Build and Test' - inputs: - scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py' - arguments: --config Debug --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --parallel --use_vcpkg --use_vcpkg_ms_internal_asset_cache --cmake_generator "Visual Studio 17 2022" --disable_memleak_checker --enable_address_sanitizer - workingDirectory: '$(Build.BinariesDirectory)' - - -- stage: x64_release - dependsOn: [] - jobs: - - template: templates/jobs/win-ci-vs-2022-job.yml - parameters: - BuildConfig: 'RelWithDebInfo' - buildArch: x64 - # Compare to our Nuget packaging pipeline, this job has "--build_wheel" but doesn't have "--enable_lto --disable_rtti --use_telemetry --enable_wcos" - # Python bindings use typeid so I can't disable RTTI here. If it causes a problem, we will need to split this job to two jobs. - additionalBuildFlags: --build_wheel --build_java --build_nodejs --msbuild_extra_options IncludeMobileTargets=false --build_nuget --use_vcpkg --use_vcpkg_ms_internal_asset_cache - msbuildPlatform: x64 - isX86: false - job_name_suffix: x64_release - RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - isTraining: false - ORT_EP_NAME: CPU - GenerateDocumentation: false - WITH_CACHE: false - MachinePool: 'onnxruntime-Win-CPU-2022' - -- stage: x64_release_dnnl - dependsOn: [] - jobs: - - template: templates/jobs/win-ci-vs-2022-job.yml - parameters: - BuildConfig: 'RelWithDebInfo' - buildArch: x64 - additionalBuildFlags: --build_wheel --use_dnnl --use_vcpkg --use_vcpkg_ms_internal_asset_cache - msbuildPlatform: x64 - isX86: false - job_name_suffix: x64_release - RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - isTraining: false - ORT_EP_NAME: DNNL - GenerateDocumentation: false - WITH_CACHE: false - # Intel EPs require Intel CPUs - MachinePool: 'onnxruntime-Win2022-Intel-CPU' - -# Tests doesn't work on AMD CPUs -- stage: x64_release_xnnpack - dependsOn: [] - jobs: - - template: templates/jobs/win-ci-vs-2022-job.yml - parameters: - BuildConfig: 'RelWithDebInfo' - buildArch: x64 - additionalBuildFlags: --build_wheel --use_xnnpack --msbuild_extra_options IncludeMobileTargets=false --build_nuget --use_vcpkg --use_vcpkg_ms_internal_asset_cache - msbuildPlatform: x64 - isX86: false - job_name_suffix: x64_release - RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - isTraining: false - ORT_EP_NAME: XNNPACK - GenerateDocumentation: false - WITH_CACHE: false - MachinePool: 'onnxruntime-Win-CPU-2022' - -# Build only. Does not run any tests. -- stage: x64_release_vitisai - dependsOn: [] - jobs: - - template: templates/jobs/win-ci-vs-2022-job.yml - parameters: - BuildConfig: 'RelWithDebInfo' - buildArch: x64 - additionalBuildFlags: --build_wheel --use_vitisai --use_vcpkg --use_vcpkg_ms_internal_asset_cache - msbuildPlatform: x64 - isX86: false - job_name_suffix: x64_release - RunOnnxRuntimeTests: false - isTraining: false - ORT_EP_NAME: VITISAI - GenerateDocumentation: false - WITH_CACHE: false - MachinePool: 'onnxruntime-Win-CPU-2022' - -- stage: x64_release_winml - dependsOn: [] - jobs: - - template: templates/jobs/win-ci-vs-2022-job.yml - parameters: - BuildConfig: 'RelWithDebInfo' - buildArch: x64 - additionalBuildFlags: --use_winml --enable_wcos --disable_rtti --msbuild_extra_options IncludeMobileTargets=false --build_nuget --use_vcpkg --use_vcpkg_ms_internal_asset_cache - msbuildPlatform: x64 - isX86: false - job_name_suffix: x64_release_winml - RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - # WinML has many warnings - EnablePython: false - isTraining: false - ORT_EP_NAME: CPU - GenerateDocumentation: false - WITH_CACHE: false - MachinePool: 'onnxruntime-Win-CPU-2022' - -- stage: x64_release_ep_generic_interface - dependsOn: [] - jobs: - - template: templates/jobs/win-ci-vs-2022-job.yml - parameters: - BuildConfig: 'RelWithDebInfo' - buildArch: x64 - additionalBuildFlags: --enable_generic_interface --use_vcpkg --use_vcpkg_ms_internal_asset_cache - msbuildPlatform: x64 - isX86: false - job_name_suffix: x64_release_ep_generic_interface - RunOnnxRuntimeTests: false # --enable_generic_interface does not build tests - EnablePython: false - isTraining: false - ORT_EP_NAME: CPU - GenerateDocumentation: false - WITH_CACHE: false - MachinePool: 'onnxruntime-Win-CPU-2022' - -- stage: x86_release - dependsOn: [] - jobs: - - template: templates/jobs/win-ci-vs-2022-job.yml - parameters: - BuildConfig: 'RelWithDebInfo' - EnvSetupScript: setup_env_x86.bat - buildArch: x86 - additionalBuildFlags: --build_wheel --msbuild_extra_options IncludeMobileTargets=false --build_nuget --use_vcpkg --use_vcpkg_ms_internal_asset_cache - msbuildPlatform: Win32 - isX86: true - job_name_suffix: x86_release - RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - isTraining: false - ORT_EP_NAME: CPU - GenerateDocumentation: false - WITH_CACHE: false - MachinePool: 'onnxruntime-Win-CPU-2022' - -- stage: ort_training_apis_x64_release - dependsOn: [] - jobs: - - template: templates/jobs/win-ci-vs-2022-job.yml - parameters: - BuildConfig: 'RelWithDebInfo' - buildArch: x64 - additionalBuildFlags: --enable_training_apis --msbuild_extra_options IncludeMobileTargets=false --build_nuget --use_vcpkg --use_vcpkg_ms_internal_asset_cache - msbuildPlatform: x64 - isX86: false - job_name_suffix: ort_training_apis_x64_release - RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - EnablePython: false - isTraining: true - ORT_EP_NAME: CPU - GenerateDocumentation: false - WITH_CACHE: false - MachinePool: 'onnxruntime-Win2022-CPU-training-AMD' - -- stage: x64_release_azure - dependsOn: [] - jobs: - - job: x64_release_azure - steps: - - powershell: | - Write-Host "##vso[task.prependpath]$(Build.BinariesDirectory)\RelWithDebInfo\_deps\vcpkg-src\installed\x86-windows\bin" - $env:PATH - Write-Host "##vso[task.prependpath]$(Build.BinariesDirectory)\RelWithDebInfo\_deps\vcpkg-src\installed\x64-windows\bin" - $env:PATH - displayName: 'Append x64-windows and x86-windows to PATH' - - template: templates/jobs/win-ci-vs-2022-job.yml - parameters: - BuildConfig: 'RelWithDebInfo' - buildArch: x64 - additionalBuildFlags: --use_azure --use_lock_free_queue --msbuild_extra_options IncludeMobileTargets=false --build_nuget --use_vcpkg --use_vcpkg_ms_internal_asset_cache - msbuildPlatform: x64 - isX86: false - job_name_suffix: x64_release_azure - RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - EnablePython: false - isTraining: false - ORT_EP_NAME: CPU - GenerateDocumentation: false - WITH_CACHE: false - MachinePool: 'onnxruntime-Win-CPU-2022' diff --git a/tools/ci_build/github/azure-pipelines/win-gpu-cuda-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/win-gpu-cuda-ci-pipeline.yml deleted file mode 100644 index cbebcad2af986..0000000000000 --- a/tools/ci_build/github/azure-pipelines/win-gpu-cuda-ci-pipeline.yml +++ /dev/null @@ -1,65 +0,0 @@ -##### start trigger Don't edit it manually, Please do edit set-trigger-rules.py #### -### please do rerun set-trigger-rules.py ### -trigger: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -pr: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -#### end trigger #### - -parameters: -- name: CudaVersion - displayName: CUDA version - type: string - default: '12.2' - values: - - 11.8 - - 12.2 -- name: RunOnnxRuntimeTests - displayName: Run Tests? - type: boolean - default: true - -stages: -- stage: cuda - dependsOn: [] - jobs: - - template: templates/jobs/win-ci-vs-2022-job.yml - parameters: - BuildConfig: 'RelWithDebInfo' - EnvSetupScript: setup_env_cuda.bat - buildArch: x64 - additionalBuildFlags: >- - --build_wheel --build_java --build_nodejs --use_cuda --cuda_home="$(Agent.TempDirectory)\v${{ parameters.CudaVersion }}" - --enable_cuda_profiling --enable_transformers_tool_test - --use_vcpkg --use_vcpkg_ms_internal_asset_cache --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=86 - --cmake_extra_defines onnxruntime_BUILD_UNIT_TESTS=ON - --cmake_extra_defines onnxruntime_ENABLE_CUDA_EP_INTERNAL_TESTS=ON - msbuildPlatform: x64 - isX86: false - job_name_suffix: x64_RelWithDebInfo - RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - ORT_EP_NAME: CUDA - WITH_CACHE: true - MachinePool: onnxruntime-Win2022-GPU-A10 \ No newline at end of file diff --git a/tools/ci_build/github/azure-pipelines/win-gpu-dml-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/win-gpu-dml-ci-pipeline.yml deleted file mode 100644 index 82ca32e65261c..0000000000000 --- a/tools/ci_build/github/azure-pipelines/win-gpu-dml-ci-pipeline.yml +++ /dev/null @@ -1,53 +0,0 @@ -##### start trigger Don't edit it manually, Please do edit set-trigger-rules.py #### -### please do rerun set-trigger-rules.py ### -trigger: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -pr: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -#### end trigger #### - -parameters: -- name: RunOnnxRuntimeTests - displayName: Run Tests? - type: boolean - default: true - -stages: -- stage: dml - dependsOn: [] - jobs: - - template: templates/jobs/win-ci-vs-2022-job.yml - parameters: - BuildConfig: 'RelWithDebInfo' - EnvSetupScript: setup_env.bat - buildArch: x64 - additionalBuildFlags: --build_wheel --use_dml --enable_wcos --use_winml --use_vcpkg --use_vcpkg_ms_internal_asset_cache - msbuildPlatform: x64 - isX86: false - job_name_suffix: x64_RelWithDebInfo - RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - ORT_EP_NAME: DML - WITH_CACHE: false - MachinePool: onnxruntime-Win2022-GPU-dml-A10 \ No newline at end of file diff --git a/tools/ci_build/github/azure-pipelines/win-gpu-doc-gen-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/win-gpu-doc-gen-ci-pipeline.yml index 3b98eae952ed1..c20f4a2c1bd19 100644 --- a/tools/ci_build/github/azure-pipelines/win-gpu-doc-gen-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/win-gpu-doc-gen-ci-pipeline.yml @@ -50,7 +50,7 @@ stages: additionalBuildFlags: >- --gen_doc validate --skip_tests --build_wheel --use_dml --use_cuda --cuda_home="$(Agent.TempDirectory)\v${{ parameters.CudaVersion }}" - --use_vcpkg --use_vcpkg_ms_internal_asset_cache --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=86 + --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=86 --cmake_extra_defines onnxruntime_BUILD_UNIT_TESTS=OFF msbuildPlatform: x64 isX86: false diff --git a/tools/ci_build/github/azure-pipelines/win-gpu-reduce-op-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/win-gpu-reduce-op-ci-pipeline.yml index 211541a18546f..bf909ad0605fe 100644 --- a/tools/ci_build/github/azure-pipelines/win-gpu-reduce-op-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/win-gpu-reduce-op-ci-pipeline.yml @@ -48,7 +48,3 @@ jobs: python $(Build.SourcesDirectory)\tools\ci_build\build.py --config $(BuildConfig) --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --test --cmake_generator "Visual Studio 17 2022" --build_shared_lib --enable_onnx_tests --use_cuda --cuda_home="$(Agent.TempDirectory)\v11.8" --cmake_extra_defines "CMAKE_CUDA_ARCHITECTURES=75" --include_ops_by_config="$(Build.SourcesDirectory)\onnxruntime\test\testdata\required_ops.config" workingDirectory: '$(Build.BinariesDirectory)\$(BuildConfig)\$(BuildConfig)' displayName: 'Run tests' - - - template: templates/component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' diff --git a/tools/ci_build/github/azure-pipelines/win-gpu-tensorrt-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/win-gpu-tensorrt-ci-pipeline.yml deleted file mode 100644 index 3d3e53b680d45..0000000000000 --- a/tools/ci_build/github/azure-pipelines/win-gpu-tensorrt-ci-pipeline.yml +++ /dev/null @@ -1,98 +0,0 @@ -##### start trigger Don't edit it manually, Please do edit set-trigger-rules.py #### -### please do rerun set-trigger-rules.py ### -trigger: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -pr: - branches: - include: - - main - - rel-* - paths: - exclude: - - docs/** - - README.md - - CONTRIBUTING.md - - BUILD.md - - 'js/web' - - 'onnxruntime/core/providers/js' -#### end trigger #### -parameters: -- name: CudaVersion - displayName: CUDA version - type: string - default: '12.2' - values: - - 11.8 - - 12.2 - -variables: - - template: templates/common-variables.yml - - name: win_trt_folder - ${{ if eq(parameters.CudaVersion, '11.8') }}: - value: ${{ variables.win_trt_folder_cuda11 }} - ${{ if eq(parameters.CudaVersion, '12.2') }}: - value: ${{ variables.win_trt_folder_cuda12 }} - -jobs: -- job: 'build' - pool: 'onnxruntime-Win2022-GPU-A10' - variables: - MsbuildArguments: '-detailedsummary -maxcpucount -consoleloggerparameters:PerformanceSummary' - EnvSetupScript: setup_env_trt.bat - skipComponentGovernanceDetection: true - TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] - timeoutInMinutes: 180 - workspace: - clean: all - steps: - - template: templates/jobs/win-ci-prebuild-steps.yml - parameters: - EnvSetupScript: $(EnvSetupScript) - DownloadCUDA: true - DownloadTRT: true - BuildArch: 'x64' - BuildConfig: RelWithDebInfo - MachinePool: 'onnxruntime-Win2022-GPU-A10' - WithCache: true - Today: $(Today) - - - template: templates/jobs/win-ci-build-steps.yml - parameters: - WithCache: True - Today: $(TODAY) - AdditionalKey: "gpu-tensorrt | RelWithDebInfo" - BuildPyArguments: '--config RelWithDebInfo --parallel --use_binskim_compliant_compile_flags --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --update --cmake_generator "Visual Studio 17 2022" --build_wheel --enable_onnx_tests --use_tensorrt --tensorrt_home="$(Agent.TempDirectory)\${{ variables.win_trt_folder }}" --cuda_home="$(Agent.TempDirectory)\v${{ parameters.CudaVersion }}" --use_vcpkg --use_vcpkg_ms_internal_asset_cache --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=86' - MsbuildArguments: $(MsbuildArguments) - BuildArch: 'x64' - Platform: 'x64' - BuildConfig: RelWithDebInfo - - - task: PythonScript@0 - displayName: 'Build wheel' - inputs: - scriptPath: '$(Build.SourcesDirectory)\setup.py' - arguments: 'bdist_wheel' - workingDirectory: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo' - - - script: | - mklink /D /J $(Build.BinariesDirectory)\RelWithDebInfo\models $(Build.BinariesDirectory)\models - DIR dist\ /S /B > wheel_filename_file - set /p WHEEL_FILENAME=- - --build_nodejs - --use_webgpu - --cmake_extra_defines onnxruntime_BUILD_UNIT_TESTS=ON onnxruntime_BUILD_DAWN_MONOLITHIC_LIBRARY=ON - msbuildPlatform: x64 - isX86: false - job_name_suffix: x64_RelWithDebInfo - RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - ORT_EP_NAME: WebGPU - EnablePython: false - WITH_CACHE: true - MachinePool: onnxruntime-Win2022-VS2022-webgpu-A10 - -- stage: webgpu_external_dawn - dependsOn: [] - jobs: - - job: build_x64_RelWithDebInfo - variables: - DEPS_CACHE_DIR: $(Agent.TempDirectory)/deps_ccache - ORT_CACHE_DIR: $(Agent.TempDirectory)/ort_ccache - TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] - workspace: - clean: all - pool: onnxruntime-Win2022-VS2022-webgpu-A10 - timeoutInMinutes: 300 - steps: - - checkout: self - clean: true - submodules: none - - - template: templates/jobs/win-ci-prebuild-steps.yml - parameters: - EnvSetupScript: setup_env.bat - DownloadCUDA: false - DownloadTRT: false - BuildArch: x64 - BuildConfig: RelWithDebInfo - MachinePool: onnxruntime-Win2022-VS2022-webgpu-A10 - WithCache: true - Today: $(Today) - - - template: templates/jobs/win-ci-build-steps.yml - parameters: - WithCache: true - Today: $(TODAY) - CacheDir: $(ORT_CACHE_DIR) - AdditionalKey: " $(System.StageName) | RelWithDebInfo " - BuildPyArguments: '--config RelWithDebInfo --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --update --parallel --cmake_generator "Visual Studio 17 2022" --use_webgpu --use_external_dawn --skip_tests --target onnxruntime_webgpu_external_dawn_test' - MsbuildArguments: '-maxcpucount' - BuildArch: x64 - Platform: x64 - BuildConfig: RelWithDebInfo - - - script: | - onnxruntime_webgpu_external_dawn_test.exe - displayName: Run tests (onnxruntime_webgpu_external_dawn_test) - workingDirectory: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo' - - script: | - onnxruntime_webgpu_external_dawn_test.exe --no_proc_table - displayName: Run tests (onnxruntime_webgpu_external_dawn_test) - workingDirectory: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo' diff --git a/tools/ci_build/github/azure-pipelines/win-qnn-arm64-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/win-qnn-arm64-ci-pipeline.yml index e08d7eb2b12de..6ea497fab6a8a 100644 --- a/tools/ci_build/github/azure-pipelines/win-qnn-arm64-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/win-qnn-arm64-ci-pipeline.yml @@ -33,7 +33,7 @@ parameters: - name: QnnSdk displayName: QNN SDK version type: string - default: 2.31.0.250130 + default: 2.32.0.250228 jobs: - job: 'BUILD_QNN_EP' @@ -90,7 +90,7 @@ jobs: --config $(BuildConfig) --build_dir $(Build.BinariesDirectory) --cmake_generator "Visual Studio 17 2022" - --build_shared_lib + --build_shared_lib --use_vcpkg --use_vcpkg_ms_internal_asset_cache --use_qnn $(QnnLibKind) --qnn_home $(QnnSDKRootDir) --update --build --parallel diff --git a/tools/ci_build/github/azure-pipelines/win-qnn-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/win-qnn-ci-pipeline.yml index 81de3335a07d2..eea2af585595a 100644 --- a/tools/ci_build/github/azure-pipelines/win-qnn-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/win-qnn-ci-pipeline.yml @@ -33,7 +33,7 @@ parameters: - name: QnnSdk displayName: QNN SDK version type: string - default: 2.31.0.250130 + default: 2.32.0.250228 jobs: - job: 'BUILD_QNN_EP' diff --git a/tools/ci_build/github/linux/build_nodejs_package.sh b/tools/ci_build/github/linux/build_nodejs_package.sh new file mode 100755 index 0000000000000..29ee91a122e39 --- /dev/null +++ b/tools/ci_build/github/linux/build_nodejs_package.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -e -x +mkdir -p $HOME/.onnx +docker run -e SYSTEM_COLLECTIONURI --rm --volume /data/onnx:/data/onnx:ro --volume $BUILD_SOURCESDIRECTORY:/onnxruntime_src --volume $BUILD_BINARIESDIRECTORY:/build \ +--volume /data/models:/build/models:ro --volume $HOME/.onnx:/home/onnxruntimedev/.onnx -e NIGHTLY_BUILD onnxruntimecuda${CUDA_VERSION_MAJOR}xtrt86build \ +/bin/bash -c "/usr/bin/python3 /onnxruntime_src/tools/ci_build/build.py --build_dir /build --config Release --skip_tests --skip_submodule_sync --parallel --use_binskim_compliant_compile_flags --build_shared_lib --build_nodejs --use_webgpu --use_tensorrt --cuda_version=$CUDA_VERSION --cuda_home=/usr/local/cuda-$CUDA_VERSION --cudnn_home=/usr --tensorrt_home=/usr --cmake_extra_defines 'CMAKE_CUDA_ARCHITECTURES=60-real;70-real;75-real;80-real;90' --use_vcpkg --use_vcpkg_ms_internal_asset_cache && cd /build/Release && make install DESTDIR=/build/installed" diff --git a/tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda b/tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda index c42042b0ec639..6552c423617b5 100644 --- a/tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda +++ b/tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda @@ -5,7 +5,7 @@ ARG BASEIMAGE=nvidia/cuda:12.5.1-cudnn-devel-ubi8 FROM $BASEIMAGE -ARG TRT_VERSION +ARG TRT_VERSION=10.9.0.34-1.cuda12.8 #Install TensorRT only if TRT_VERSION is not empty RUN if [ -n "$TRT_VERSION" ]; then \ diff --git a/tools/ci_build/github/linux/docker/Dockerfile.package_ubi8_cuda11_8_tensorrt8_6 b/tools/ci_build/github/linux/docker/Dockerfile.package_ubi8_cuda11_8_tensorrt8_6 deleted file mode 100644 index 9de88d1664b82..0000000000000 --- a/tools/ci_build/github/linux/docker/Dockerfile.package_ubi8_cuda11_8_tensorrt8_6 +++ /dev/null @@ -1,46 +0,0 @@ -# -------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. -# -------------------------------------------------------------- -# Dockerfile to Test ONNX Runtime on UBI8 with CUDA 11.8 and TensorRT 8.6 - -# Build base image with required system packages -ARG BASEIMAGE=nvidia/cuda:11.8.0-cudnn8-devel-ubi8 -ARG TRT_VERSION=8.6.1.6-1.cuda11.8 -FROM $BASEIMAGE AS base -ARG TRT_VERSION -ENV PATH=/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/src/tensorrt/bin:${PATH} - -RUN dnf install -y bash wget &&\ - dnf clean dbcache - -# Install python3 -RUN dnf install -y \ - python3.10 \ - python310-pip \ - python310-wheel &&\ - cd /usr/local/bin &&\ - ln -s /usr/bin/python3 python3.10 &&\ - ln -s /usr/bin/pip3 pip3.10; - -RUN pip3 install --upgrade pip -RUN pip3 install setuptools>=68.2.2 - -# Install TensorRT -RUN dnf install -y libnvinfer8 libnvonnxparsers8 libnvparsers8 libnvinfer-plugin8 libnvinfer-lean8 libnvinfer-vc-plugin8 libnvinfer-dispatch8 -RUN dnf downgrade -y libnvinfer8-${TRT_VERSION} libnvinfer8-${TRT_VERSION} libnvonnxparsers8-${TRT_VERSION} libnvparsers8-${TRT_VERSION} libnvinfer-plugin8-${TRT_VERSION} libnvinfer-lean8-${TRT_VERSION} libnvinfer-vc-plugin8-${TRT_VERSION} libnvinfer-dispatch8-${TRT_VERSION} &&\ - dnf install -y dnf-plugin-versionlock &&\ - dnf versionlock libnvinfer8 libnvonnxparsers8 libnvparsers8 libnvinfer-plugin8 libnvinfer-lean8 libnvinfer-vc-plugin8 libnvinfer-dispatch8 -RUN dnf clean dbcache - - -ADD scripts /tmp/scripts -RUN cd /tmp/scripts && /tmp/scripts/install_dotnet.sh && /tmp/scripts/install_java.sh && rm -rf /tmp/scripts - -# Build final image from base. -FROM base as final -ARG BUILD_USER=onnxruntimedev -ARG BUILD_UID=1000 -RUN adduser --uid $BUILD_UID $BUILD_USER -WORKDIR /home/$BUILD_USER -USER $BUILD_USER diff --git a/tools/ci_build/github/linux/docker/Dockerfile.package_ubi8_cuda_tensorrt10_0 b/tools/ci_build/github/linux/docker/Dockerfile.package_ubi8_cuda_tensorrt10_0 index 7abc7a6d35ec3..1933fd371d3bc 100644 --- a/tools/ci_build/github/linux/docker/Dockerfile.package_ubi8_cuda_tensorrt10_0 +++ b/tools/ci_build/github/linux/docker/Dockerfile.package_ubi8_cuda_tensorrt10_0 @@ -6,7 +6,7 @@ # Build base image with required system packages ARG BASEIMAGE=nvidia/cuda:12.5.1-cudnn-devel-ubi8 -ARG TRT_VERSION=10.8.0.43-1.cuda12.8 +ARG TRT_VERSION=10.9.0.34-1.cuda12.8 FROM $BASEIMAGE AS base ARG TRT_VERSION ENV PATH=/opt/python/cp310-cp310/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/src/tensorrt/bin:${PATH} diff --git a/tools/ci_build/github/linux/docker/Dockerfile.package_ubi8_cuda_tensorrt10_0_torch b/tools/ci_build/github/linux/docker/Dockerfile.package_ubi8_cuda_tensorrt10_0_torch index 2df43197b7d39..62562705c92b2 100644 --- a/tools/ci_build/github/linux/docker/Dockerfile.package_ubi8_cuda_tensorrt10_0_torch +++ b/tools/ci_build/github/linux/docker/Dockerfile.package_ubi8_cuda_tensorrt10_0_torch @@ -6,7 +6,7 @@ # Build base image with required system packages ARG BASEIMAGE=nvidia/cuda:11.8.0-cudnn8-devel-ubi8 -ARG TRT_VERSION=10.8.0.43-1.cuda11.8 +ARG TRT_VERSION=10.9.0.34-1.cuda11.8 FROM $BASEIMAGE AS base ARG TRT_VERSION ENV PATH=/opt/python/cp310-cp310/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/src/tensorrt/bin:${PATH} diff --git a/tools/ci_build/github/linux/docker/Dockerfile.package_ubuntu_2004_gpu b/tools/ci_build/github/linux/docker/Dockerfile.package_ubuntu_2004_gpu index 64186e83f001a..8a84b9b940306 100644 --- a/tools/ci_build/github/linux/docker/Dockerfile.package_ubuntu_2004_gpu +++ b/tools/ci_build/github/linux/docker/Dockerfile.package_ubuntu_2004_gpu @@ -5,8 +5,8 @@ # Dockerfile to run ONNXRuntime with TensorRT integration # Build base image with required system packages -ARG BASEIMAGE=nvidia/cuda:11.8.0-cudnn8-devel-ubuntu20.04 -ARG TRT_VERSION=10.8.0.43-1+cuda11.8 +ARG BASEIMAGE=nvidia/cuda:12.2.2-cudnn8-devel-ubuntu20.04 +ARG TRT_VERSION=10.9.0.34-1+cuda12.8 ARG LD_LIBRARY_PATH_ARG=/usr/local/lib64:/usr/local/cuda/lib64 FROM $BASEIMAGE AS base ARG TRT_VERSION diff --git a/tools/ci_build/github/linux/docker/Dockerfile.package_ubuntu_2204_gpu_ffmpeg b/tools/ci_build/github/linux/docker/Dockerfile.package_ubuntu_2204_gpu_ffmpeg index a987d511ddc6d..bf3b50880a252 100644 --- a/tools/ci_build/github/linux/docker/Dockerfile.package_ubuntu_2204_gpu_ffmpeg +++ b/tools/ci_build/github/linux/docker/Dockerfile.package_ubuntu_2204_gpu_ffmpeg @@ -5,8 +5,8 @@ # Dockerfile to run ONNXRuntime with TensorRT integration # Build base image with required system packages -ARG BASEIMAGE=nvidia/cuda:11.8.0-cudnn8-devel-ubuntu22.04 -ARG TRT_VERSION=10.8.0.43-1+cuda11.8 +ARG BASEIMAGE=nvidia/cuda:12.8.1-cudnn-devel-ubuntu22.04 +ARG TRT_VERSION=10.9.0.34-1+cuda12.8 ARG LD_LIBRARY_PATH_ARG=/usr/local/lib64:/usr/local/cuda/lib64 FROM $BASEIMAGE AS base ARG TRT_VERSION @@ -28,7 +28,7 @@ RUN apt-get install -y --no-install-recommends \ RUN pip install --upgrade pip # Install TensorRT -RUN apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/7fa2af80.pub &&\ +RUN apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/7fa2af80.pub &&\ apt-get update &&\ apt-get install -y \ libnvinfer-dev=${TRT_VERSION} \ @@ -57,6 +57,9 @@ RUN if [ -n "/tmp/ompffmpeg" ]; then \ ln -s /tmp/ompffmpeg/ffmpeg /usr/local/bin/ffmpeg; ln -s /tmp/ompffmpeg/ffprobe /usr/local/bin/ffprobe; \ fi +# Install ninja +RUN apt-get update && apt-get install -y ninja-build + # Build final image from base. FROM base as final ARG BUILD_USER=onnxruntimedev diff --git a/tools/ci_build/github/linux/docker/Dockerfile.package_ubuntu_2204_gpu_opencv b/tools/ci_build/github/linux/docker/Dockerfile.package_ubuntu_2204_gpu_opencv index 7f5e8f871f415..c6931147f96f9 100644 --- a/tools/ci_build/github/linux/docker/Dockerfile.package_ubuntu_2204_gpu_opencv +++ b/tools/ci_build/github/linux/docker/Dockerfile.package_ubuntu_2204_gpu_opencv @@ -5,8 +5,8 @@ # Dockerfile to run ONNXRuntime with TensorRT integration # Build base image with required system packages -ARG BASEIMAGE=nvidia/cuda:11.8.0-cudnn8-devel-ubuntu22.04 -ARG TRT_VERSION=10.8.0.43-1+cuda11.8 +ARG BASEIMAGE=nvidia/cuda:12.8.1-cudnn-devel-ubuntu22.04 +ARG TRT_VERSION=10.9.0.34-1+cuda12.8 ARG LD_LIBRARY_PATH_ARG=/usr/local/lib64:/usr/local/cuda/lib64 FROM $BASEIMAGE AS base ARG TRT_VERSION @@ -30,7 +30,7 @@ RUN apt-get install -y --no-install-recommends \ RUN pip install --upgrade pip # Install TensorRT -RUN apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/7fa2af80.pub &&\ +RUN apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/7fa2af80.pub &&\ apt-get update &&\ apt-get install -y \ libnvinfer-dev=${TRT_VERSION} \ diff --git a/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_cuda11_tensorrt10 b/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_cuda11_tensorrt10 deleted file mode 100644 index f454d21164ac4..0000000000000 --- a/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_cuda11_tensorrt10 +++ /dev/null @@ -1,109 +0,0 @@ -# -------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. -# -------------------------------------------------------------- -# Dockerfile to run ONNXRuntime with TensorRT integration - -# Build base image with required system packages -FROM nvidia/cuda:11.8.0-cudnn8-devel-ubuntu22.04 AS base - -# The local directory into which to build and install CMAKE -ARG ONNXRUNTIME_LOCAL_CODE_DIR=/code - -ENV PATH=/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/src/tensorrt/bin:${ONNXRUNTIME_LOCAL_CODE_DIR}/cmake-3.31.5-linux-x86_64/bin:/opt/miniconda/bin:${PATH} -ENV DEBIAN_FRONTEND=noninteractive - -RUN apt-get update &&\ - apt-get install -y sudo git bash unattended-upgrades wget -RUN unattended-upgrade - -# Install python3 -RUN apt-get install -y --no-install-recommends \ - python3 \ - python3-pip \ - python3-dev \ - python3-wheel &&\ - cd /usr/local/bin &&\ - ln -s /usr/bin/python3 python &&\ - ln -s /usr/bin/pip3 pip; - -RUN pip install --upgrade pip -RUN pip install psutil setuptools>=68.2.2 - -# Install TensorRT -RUN TRT_VERSION="10.8.0.43-1+cuda11.8" &&\ - apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/7fa2af80.pub &&\ - apt-get update &&\ - apt-get install -y \ - libnvinfer-dev=${TRT_VERSION} \ - libnvinfer-dispatch-dev=${TRT_VERSION} \ - libnvinfer-dispatch10=${TRT_VERSION} \ - libnvinfer-headers-dev=${TRT_VERSION} \ - libnvinfer-headers-plugin-dev=${TRT_VERSION} \ - libnvinfer-lean-dev=${TRT_VERSION} \ - libnvinfer-lean10=${TRT_VERSION} \ - libnvinfer-plugin-dev=${TRT_VERSION} \ - libnvinfer-plugin10=${TRT_VERSION} \ - libnvinfer-vc-plugin-dev=${TRT_VERSION} \ - libnvinfer-vc-plugin10=${TRT_VERSION} \ - libnvinfer10=${TRT_VERSION} \ - libnvonnxparsers-dev=${TRT_VERSION} \ - libnvonnxparsers10=${TRT_VERSION} \ - tensorrt-dev=${TRT_VERSION} \ - libnvinfer-bin=${TRT_VERSION} - -# Compile trtexec if not installed -RUN if [ ! -d /usr/src/tensorrt/bin ] || [ ! -f /usr/src/tensorrt/bin/trtexec ]; then \ - cd /usr/src/tensorrt/samples/trtexec && make; \ - fi - -# Install Valgrind -RUN apt-get install -y valgrind - -# Build final image from base. Builds ORT. -FROM base AS final -ARG BUILD_USER=onnxruntimedev -ARG BUILD_UID=1000 -RUN adduser --gecos 'onnxruntime Build User' --disabled-password $BUILD_USER --uid $BUILD_UID -USER $BUILD_USER - -# ONNX Runtime arguments - -# URL to the github repo from which to clone ORT. -ARG ONNXRUNTIME_REPO=https://github.com/Microsoft/onnxruntime - -# The local directory into which to clone ORT. -ARG ONNXRUNTIME_LOCAL_CODE_DIR=/code - -# The git branch of ORT to checkout and build. -ARG ONNXRUNTIME_BRANCH=main - -# Optional. The specific commit to pull and build from. If not set, the latest commit is used. -ARG ONNXRUNTIME_COMMIT_ID - -# The supported CUDA architecture -ARG CMAKE_CUDA_ARCHITECTURES=75 - -WORKDIR ${ONNXRUNTIME_LOCAL_CODE_DIR} - -# Clone ORT repository with branch -RUN git clone --single-branch --branch ${ONNXRUNTIME_BRANCH} --recursive ${ONNXRUNTIME_REPO} onnxruntime &&\ - /bin/sh onnxruntime/dockerfiles/scripts/install_common_deps.sh - -WORKDIR ${ONNXRUNTIME_LOCAL_CODE_DIR}/onnxruntime - -# Reset to a specific commit if specified by build args. -RUN if [ -z "$ONNXRUNTIME_COMMIT_ID" ] ; then echo "Building branch ${ONNXRUNTIME_BRANCH}" ;\ - else echo "Building branch ${ONNXRUNTIME_BRANCH} @ commit ${ONNXRUNTIME_COMMIT_ID}" &&\ - git reset --hard ${ONNXRUNTIME_COMMIT_ID} && git submodule update --recursive ; fi - -# Build ORT -ENV CUDA_MODULE_LOADING="LAZY" -ARG PARSER_CONFIG="" -RUN /bin/sh build.sh ${PARSER_CONFIG} --parallel --build_shared_lib --cuda_home /usr/local/cuda --cudnn_home /usr/lib/x86_64-linux-gnu/ --use_tensorrt --tensorrt_home /usr/lib/x86_64-linux-gnu/ --config Release --build_wheel --skip_tests --skip_submodule_sync --cmake_extra_defines '"CMAKE_CUDA_ARCHITECTURES='${CMAKE_CUDA_ARCHITECTURES}'"' - -# Switch to root to continue following steps of CI -USER root - -# Intall ORT wheel -RUN pip install ${ONNXRUNTIME_LOCAL_CODE_DIR}/onnxruntime/build/Linux/Release/dist/*.whl diff --git a/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_cuda12_tensorrt10 b/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_cuda12_tensorrt10 index a9dbefc6faee0..1d3575411a692 100644 --- a/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_cuda12_tensorrt10 +++ b/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_cuda12_tensorrt10 @@ -5,7 +5,7 @@ # Dockerfile to run ONNXRuntime with TensorRT integration # Build base image with required system packages -FROM nvidia/cuda:12.6.3-cudnn-devel-ubuntu22.04 AS base +FROM nvidia/cuda:12.8.0-cudnn-devel-ubuntu22.04 AS base # The local directory into which to build and install CMAKE ARG ONNXRUNTIME_LOCAL_CODE_DIR=/code @@ -31,7 +31,7 @@ RUN pip install --upgrade pip RUN pip install setuptools>=68.2.2 psutil # Install TensorRT -RUN TRT_VERSION="10.8.0.43-1+cuda12.8" &&\ +RUN TRT_VERSION="10.9.0.34-1+cuda12.8" &&\ apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/7fa2af80.pub &&\ apt-get update &&\ apt-get install -y \ diff --git a/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_openvino b/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_openvino index 7b1e3fa677375..b53a2302be403 100644 --- a/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_openvino +++ b/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_openvino @@ -1,7 +1,7 @@ ARG UBUNTU_VERSION=22.04 FROM ubuntu:${UBUNTU_VERSION} -ARG OPENVINO_VERSION=2024.5.0 +ARG OPENVINO_VERSION=2025.0.0 ARG PYTHON_VERSION=3.10 ADD scripts /tmp/scripts @@ -19,9 +19,9 @@ ENV IE_PLUGINS_PATH=$INTEL_OPENVINO_DIR/runtime/lib/intel64 ENV DEBIAN_FRONTEND=noninteractive RUN cd /opt && mkdir -p intel && cd intel && \ - wget https://storage.openvinotoolkit.org/repositories/openvino/packages/2024.5/linux/l_openvino_toolkit_ubuntu22_2024.5.0.17288.7975fa5da0c_x86_64.tgz && \ - tar xzf l_openvino_toolkit_ubuntu22_2024.5.0.17288.7975fa5da0c_x86_64.tgz && rm -rf l_openvino_toolkit_ubuntu22_2024.5.0.17288.7975fa5da0c_x86_64.tgz && \ - mv l_openvino_toolkit_ubuntu22_2024.5.0.17288.7975fa5da0c_x86_64 openvino_2024.5.0 && \ + wget https://storage.openvinotoolkit.org/repositories/openvino/packages/2025.0/linux/openvino_toolkit_ubuntu22_2025.0.0.17942.1f68be9f594_x86_64.tgz && \ + tar xzf openvino_toolkit_ubuntu22_2025.0.0.17942.1f68be9f594_x86_64.tgz && rm -rf openvino_toolkit_ubuntu22_2025.0.0.17942.1f68be9f594_x86_64.tgz && \ + mv openvino_toolkit_ubuntu22_2025.0.0.17942.1f68be9f594_x86_64 openvino_2025.0.0 && \ cd $INTEL_OPENVINO_DIR/install_dependencies && ./install_openvino_dependencies.sh -y WORKDIR /root diff --git a/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_tensorrt_bin b/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_tensorrt_bin index 7dd302a6b03da..03f14732b70f8 100644 --- a/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_tensorrt_bin +++ b/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_tensorrt_bin @@ -5,7 +5,7 @@ # Dockerfile to run ONNXRuntime with TensorRT installed from provided binaries # Build base image with required system packages -FROM nvidia/cuda:12.6.3-cudnn-devel-ubuntu22.04 AS base +FROM nvidia/cuda:12.8.0-cudnn-devel-ubuntu22.04 AS base # The local directory into which to build and install CMAKE ARG ONNXRUNTIME_LOCAL_CODE_DIR=/code diff --git a/tools/ci_build/github/linux/docker/inference/x86_64/default/cuda11/Dockerfile b/tools/ci_build/github/linux/docker/inference/x86_64/default/cuda11/Dockerfile deleted file mode 100644 index 24287fd34d3ea..0000000000000 --- a/tools/ci_build/github/linux/docker/inference/x86_64/default/cuda11/Dockerfile +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -# This file is used by Zip-Nuget Packaging NoContribOps Pipeline,Zip-Nuget-Java Packaging Pipeline -FROM onnxruntimebuildcache.azurecr.io/internal/azureml/onnxruntime/build/cuda11_x64_almalinux8_gcc11_dotnet:20250124.1 - -ARG TRT_VERSION -#Install TensorRT only if TRT_VERSION is not empty -RUN if [ -n "$TRT_VERSION" ]; then \ - echo "TRT_VERSION is $TRT_VERSION" && \ - dnf -y install \ - libnvinfer10-${TRT_VERSION} \ - libnvinfer-headers-devel-${TRT_VERSION} \ - libnvinfer-devel-${TRT_VERSION} \ - libnvinfer-lean10-${TRT_VERSION} \ - libnvonnxparsers10-${TRT_VERSION} \ - libnvonnxparsers-devel-${TRT_VERSION} \ - libnvinfer-dispatch10-${TRT_VERSION} \ - libnvinfer-plugin10-${TRT_VERSION} \ - libnvinfer-vc-plugin10-${TRT_VERSION} \ - libnvinfer-bin-${TRT_VERSION} \ - libnvinfer-plugin10-${TRT_VERSION} \ - libnvinfer-plugin-devel-${TRT_VERSION} \ - libnvinfer-vc-plugin-devel-${TRT_VERSION} \ - libnvinfer-lean-devel-${TRT_VERSION} \ - libnvinfer-dispatch-devel-${TRT_VERSION} \ - libnvinfer-headers-plugin-devel-${TRT_VERSION} && \ - dnf clean dbcache ; \ -else \ - echo "TRT_VERSION is none skipping Tensor RT Installation" ; \ -fi - -ENV PATH=/usr/lib/jvm/msopenjdk-17/bin:$PATH -ENV LANG=en_US.UTF-8 -ENV LC_ALL=en_US.UTF-8 -ENV JAVA_HOME=/usr/lib/jvm/msopenjdk-17 -ENV CUDAHOSTCXX=/opt/rh/gcc-toolset-11/root/usr/bin/g++ -ADD scripts /tmp/scripts -RUN cd /tmp/scripts && /tmp/scripts/install_deps.sh && rm -rf /tmp/scripts - -ARG BUILD_UID=1001 -ARG BUILD_USER=onnxruntimedev -RUN adduser --uid $BUILD_UID $BUILD_USER -WORKDIR /home/$BUILD_USER -USER $BUILD_USER diff --git a/tools/ci_build/github/linux/docker/inference/x86_64/default/cuda11/scripts/install_deps.sh b/tools/ci_build/github/linux/docker/inference/x86_64/default/cuda11/scripts/install_deps.sh deleted file mode 100755 index e98429946f4b3..0000000000000 --- a/tools/ci_build/github/linux/docker/inference/x86_64/default/cuda11/scripts/install_deps.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash -set -e -x - -# Download a file from internet -function GetFile { - local uri=$1 - local path=$2 - local force=${3:-false} - local download_retries=${4:-5} - local retry_wait_time_seconds=${5:-30} - - if [[ -f $path ]]; then - if [[ $force = false ]]; then - echo "File '$path' already exists. Skipping download" - return 0 - else - rm -rf $path - fi - fi - - if [[ -f $uri ]]; then - echo "'$uri' is a file path, copying file to '$path'" - cp $uri $path - return $? - fi - - echo "Downloading $uri" - # Use aria2c if available, otherwise use curl - if command -v aria2c > /dev/null; then - aria2c -q -d $(dirname $path) -o $(basename $path) "$uri" - else - curl "$uri" -sSL --retry $download_retries --retry-delay $retry_wait_time_seconds --create-dirs -o "$path" --fail - fi - - return $? -} -mkdir -p /tmp/src - -cd /tmp/src - - -echo "Installing Node.js" -CPU_ARCH=`uname -m` -if [[ "$CPU_ARCH" = "x86_64" ]]; then - NODEJS_ARCH=x64 -elif [[ "$CPU_ARCH" = "aarch64" ]]; then - NODEJS_ARCH=arm64 -else - NODEJS_ARCH=$CPU_ARCH -fi -# The EOL for nodejs v18.17.1 LTS is April 2025 -GetFile https://nodejs.org/dist/v18.17.1/node-v18.17.1-linux-${NODEJS_ARCH}.tar.gz /tmp/src/node-v18.17.1-linux-${NODEJS_ARCH}.tar.gz -tar --strip 1 -xf /tmp/src/node-v18.17.1-linux-${NODEJS_ARCH}.tar.gz -C /usr - -cd / -rm -rf /tmp/src diff --git a/tools/ci_build/github/linux/docker/inference/x86_64/python/cuda/Dockerfile b/tools/ci_build/github/linux/docker/inference/x86_64/python/cuda/Dockerfile index 0c105daa38ac8..d87870db0bca8 100644 --- a/tools/ci_build/github/linux/docker/inference/x86_64/python/cuda/Dockerfile +++ b/tools/ci_build/github/linux/docker/inference/x86_64/python/cuda/Dockerfile @@ -2,10 +2,10 @@ # Please overwrite BASEIMAGE, TRT_VERSION and other arguments with # --docker-build-args ' --build-arg BASEIMAGE=other_base_image --build-arg TRT_VERSION=other_trt_version etc...' # for other cuda version and TRT version -ARG BASEIMAGE=nvidia/cuda:11.8.0-cudnn8-devel-ubi8 +ARG BASEIMAGE=nvidia/cuda:12.5.1-cudnn-devel-ubi8 FROM $BASEIMAGE -ARG TRT_VERSION=10.8.0.43-1.cuda11.8 +ARG TRT_VERSION=10.9.0.34-1.cuda12.8 #Install TensorRT only if TRT_VERSION is not empty RUN if [ -n "${TRT_VERSION}" ]; then \ diff --git a/tools/ci_build/github/linux/docker/scripts/install_os_deps.sh b/tools/ci_build/github/linux/docker/scripts/install_os_deps.sh index eba897c7c816b..c38b036159393 100755 --- a/tools/ci_build/github/linux/docker/scripts/install_os_deps.sh +++ b/tools/ci_build/github/linux/docker/scripts/install_os_deps.sh @@ -63,12 +63,7 @@ if [[ ("$DISTRIBUTOR" = "CentOS" || "$DISTRIBUTOR" = "RedHatEnterprise") && $SYS else LIBDIR="lib" fi -if [[ $SYS_LONG_BIT = "64" && "$GLIBC_VERSION" -gt "9" ]]; then - echo "Installing azcopy" - mkdir -p /tmp/azcopy - GetFile https://aka.ms/downloadazcopy-v10-linux /tmp/azcopy/azcopy.tar.gz - tar --strip 1 -xf /tmp/azcopy/azcopy.tar.gz -C /tmp/azcopy - cp /tmp/azcopy/azcopy /usr/bin +if [[ $SYS_LONG_BIT = "64" && "$GLIBC_VERSION" -gt "9" ]]; then echo "Installing cmake" GetFile https://github.com/Kitware/CMake/releases/download/v3.31.5/cmake-3.31.5-Linux-x86_64.tar.gz /tmp/src/cmake-3.31.5-Linux-x86_64.tar.gz tar -zxf /tmp/src/cmake-3.31.5-Linux-x86_64.tar.gz --strip=1 -C /usr @@ -90,10 +85,6 @@ fi cd /tmp/src -if ! [ -x "$(command -v protoc)" ]; then - $SCRIPT_DIR/install_protobuf.sh -p $INSTALL_PREFIX -fi - if [ $DEVICE_TYPE = "gpu" ]; then if [[ $INSTALL_DEPS_DISTRIBUTED_SETUP = true ]]; then source ${0/%install_os_deps.sh/install_openmpi.sh} diff --git a/tools/ci_build/github/linux/docker/scripts/manylinux/install_deps.sh b/tools/ci_build/github/linux/docker/scripts/manylinux/install_deps.sh index 5483f55c01942..ee33866e4286a 100755 --- a/tools/ci_build/github/linux/docker/scripts/manylinux/install_deps.sh +++ b/tools/ci_build/github/linux/docker/scripts/manylinux/install_deps.sh @@ -32,11 +32,6 @@ source "$LOCAL_DIR/install_shared_deps.sh" cd /tmp/src -if ! [ -x "$(command -v protoc)" ]; then -# shellcheck disable=SC1091 - source "$PARENT_DIR/install_protobuf.sh" -fi - export ONNX_ML=1 export CMAKE_ARGS="-DONNX_GEN_PB_TYPE_STUBS=OFF -DONNX_WERROR=OFF" diff --git a/tools/ci_build/github/linux/docker/scripts/manylinux/install_shared_deps.sh b/tools/ci_build/github/linux/docker/scripts/manylinux/install_shared_deps.sh index ec29fd45f07a7..6cb52aa3fbf87 100755 --- a/tools/ci_build/github/linux/docker/scripts/manylinux/install_shared_deps.sh +++ b/tools/ci_build/github/linux/docker/scripts/manylinux/install_shared_deps.sh @@ -38,12 +38,6 @@ function GetFile { cd /tmp/src -echo "Installing azcopy" -mkdir -p /tmp/azcopy -GetFile https://aka.ms/downloadazcopy-v10-linux /tmp/azcopy/azcopy.tar.gz -tar --strip 1 -xf /tmp/azcopy/azcopy.tar.gz -C /tmp/azcopy -cp /tmp/azcopy/azcopy /usr/bin - echo "Installing Node.js" # The EOL for nodejs v18.17.1 LTS is April 2025 GetFile https://nodejs.org/dist/v18.17.1/node-v18.17.1-linux-x64.tar.gz /tmp/src/node-v18.17.1-linux-x64.tar.gz diff --git a/tools/ci_build/github/linux/python/requirements.txt b/tools/ci_build/github/linux/python/requirements.txt index 36b30ed6d3d12..1a580b848a55a 100644 --- a/tools/ci_build/github/linux/python/requirements.txt +++ b/tools/ci_build/github/linux/python/requirements.txt @@ -8,3 +8,4 @@ protobuf==4.21.12 sympy==1.12 flatbuffers psutil +onnxscript==0.2.3 diff --git a/tools/ci_build/github/windows/python/requirements.txt b/tools/ci_build/github/windows/python/requirements.txt index 200b9c2e50288..2b222c4b1d4a4 100644 --- a/tools/ci_build/github/windows/python/requirements.txt +++ b/tools/ci_build/github/windows/python/requirements.txt @@ -8,3 +8,4 @@ protobuf==4.21.12 sympy==1.12 flatbuffers psutil +onnxscript==0.2.3 diff --git a/tools/ci_build/github/windows/setup_env_gpu.bat b/tools/ci_build/github/windows/setup_env_gpu.bat index fd9890fa12fb3..ecadab5d3f8a3 100644 --- a/tools/ci_build/github/windows/setup_env_gpu.bat +++ b/tools/ci_build/github/windows/setup_env_gpu.bat @@ -6,10 +6,10 @@ if exist PATH=%AGENT_TEMPDIRECTORY%\v12.2\ ( ) else ( set PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.2\bin;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.2\extras\CUPTI\lib64;%PATH% ) -set PATH=%AGENT_TEMPDIRECTORY%\TensorRT-10.8.0.43.Windows10.x86_64.cuda-12.8\lib;%PATH% +set PATH=%AGENT_TEMPDIRECTORY%\TensorRT-10.9.0.34.Windows10.x86_64.cuda-12.8\lib;%PATH% @REM The default version is still cuda v12.2, because set cuda v11.8 after it -set PATH=%PATH%;%AGENT_TEMPDIRECTORY%\TensorRT-10.8.0.43.Windows10.x86_64.cuda-11.8\lib +set PATH=%PATH%;%AGENT_TEMPDIRECTORY%\TensorRT-10.9.0.34.Windows10.x86_64.cuda-11.8\lib if exist PATH=%AGENT_TEMPDIRECTORY%\v11.8\ ( set PATH=%PATH%;%AGENT_TEMPDIRECTORY%\v11.8\bin;%AGENT_TEMPDIRECTORY%\v11.8\extras\CUPTI\lib64 ) else ( diff --git a/tools/ci_build/github/windows/setup_env_trt.bat b/tools/ci_build/github/windows/setup_env_trt.bat index f598d25353c4a..45e0d970fb541 100644 --- a/tools/ci_build/github/windows/setup_env_trt.bat +++ b/tools/ci_build/github/windows/setup_env_trt.bat @@ -6,6 +6,6 @@ if exist PATH=%AGENT_TEMPDIRECTORY%\v12.2\ ( ) else ( set PATH=%PATH%;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.2\bin;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.2\extras\CUPTI\lib64 ) -set PATH=%AGENT_TEMPDIRECTORY%\TensorRT-10.8.0.43.Windows10.x86_64.cuda-12.8\lib;%PATH% +set PATH=%AGENT_TEMPDIRECTORY%\TensorRT-10.9.0.34.Windows10.x86_64.cuda-12.8\lib;%PATH% set GRADLE_OPTS=-Dorg.gradle.daemon=false set CUDA_MODULE_LOADING=LAZY diff --git a/tools/ci_build/requirements/transformers-test/requirements.txt b/tools/ci_build/requirements/transformers-test/requirements.txt index 14aeff3df9c62..47286c364a90f 100644 --- a/tools/ci_build/requirements/transformers-test/requirements.txt +++ b/tools/ci_build/requirements/transformers-test/requirements.txt @@ -8,5 +8,7 @@ torch coloredlogs==15.0 transformers==4.46.3 parameterized>=0.8.1 +sentencepiece psutil einops +onnxscript==0.2.3 diff --git a/tools/ci_build/set-trigger-rules.py b/tools/ci_build/set-trigger-rules.py index 78f59452d1284..899aaaa95216a 100644 --- a/tools/ci_build/set-trigger-rules.py +++ b/tools/ci_build/set-trigger-rules.py @@ -16,8 +16,6 @@ "android-x86_64-crosscompile-ci-pipeline.yml", "bigmodels-ci-pipeline.yml", "linux-ci-pipeline.yml", - "linux-cpu-aten-pipeline.yml", - "linux-cpu-eager-pipeline.yml", "linux-dnnl-ci-pipeline.yml", "linux-gpu-ci-pipeline.yml", "linux-gpu-tensorrt-ci-pipeline.yml", @@ -36,6 +34,7 @@ "win-gpu-doc-gen-ci-pipeline.yml", "win-gpu-tensorrt-ci-pipeline.yml", "win-gpu-webgpu-ci-pipeline.yml", + "win-openvino-ci-pipeline.yml", "win-qnn-arm64-ci-pipeline.yml", "win-qnn-ci-pipeline.yml", ] diff --git a/tools/nuget/generate_nuspec_for_custom_nuget.py b/tools/nuget/generate_nuspec_for_custom_nuget.py new file mode 100644 index 0000000000000..baf46743cbf1b --- /dev/null +++ b/tools/nuget/generate_nuspec_for_custom_nuget.py @@ -0,0 +1,150 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import argparse +import glob +import os +import shutil + +from generate_nuspec_for_native_nuget import generate_metadata + + +def generate_files(lines, args): + files_list = [""] + platform_map = { + "win-arm64": args.win_arm64, + "win-x64": args.win_x64, + } + + avoid_keywords = {"pdb"} + processed_includes = set() + for platform, platform_dir in platform_map.items(): + for file in glob.glob(os.path.join(platform_dir, "lib", "*")): + if not os.path.isfile(file): + continue + if any(keyword in file for keyword in avoid_keywords): + continue + file_name = os.path.basename(file) + + files_list.append(f'') + + for file in glob.glob(os.path.join(platform_dir, "include", "*")): + if not os.path.isfile(file): + continue + file_name = os.path.basename(file) + if file_name in processed_includes: + continue + processed_includes.add(file_name) + files_list.append(f'') + + files_list.append( + f'' + ) + + files_list.append(f'') + files_list.append( + f'' + ) + files_list.append(f'') + files_list.append( + f'' + ) + + source_props = os.path.join( + args.root_dir, + "csharp", + "src", + "Microsoft.ML.OnnxRuntime", + "targets", + "netstandard", + "props.xml", + ) + target_props = os.path.join( + args.root_dir, + "csharp", + "src", + "Microsoft.ML.OnnxRuntime", + "targets", + "netstandard", + f"{args.package_name}.props", + ) + shutil.copyfile(source_props, target_props) + files_list.append(f'') + files_list.append(f'') + + source_targets = os.path.join( + args.root_dir, + "csharp", + "src", + "Microsoft.ML.OnnxRuntime", + "targets", + "netstandard", + "targets.xml", + ) + target_targets = os.path.join( + args.root_dir, + "csharp", + "src", + "Microsoft.ML.OnnxRuntime", + "targets", + "netstandard", + f"{args.package_name}.targets", + ) + shutil.copyfile(source_targets, target_targets) + files_list.append(f'') + files_list.append(f'') + + files_list.append("") + lines.extend(files_list) + + +def parse_arguments(): + parser = argparse.ArgumentParser( + description="Create a nuspec file for the custom nuget package.", + ) + + parser.add_argument("--nuspec_path", required=True, help="Nuspec output file path.") + parser.add_argument("--root_dir", required=True, help="ORT repository root.") + parser.add_argument( + "--commit_id", + required=True, + help="The last commit id included in this package.", + ) + parser.add_argument("--win_arm64", required=True, help="Ort win-arm64 directory") + parser.add_argument("--win_x64", required=True, help="Ort win-x64 directory") + parser.add_argument("--package_version", required=True, help="Version of the package") + parser.add_argument("--package_name", required=True, help="Name of the package") + + args = parser.parse_args() + + args.sdk_info = "" + + return args + + +def generate_nuspec(args: argparse.Namespace): + lines = [''] + lines.append("") + + generate_metadata(lines, args) + generate_files(lines, args) + + lines.append("") + return lines + + +def main(): + args = parse_arguments() + + lines = generate_nuspec(args) + + with open(os.path.join(args.nuspec_path), "w") as f: + for line in lines: + # Uncomment the printing of the line if you need to debug what's produced on a CI machine + print(line) + f.write(line) + f.write("\n") + + +if __name__ == "__main__": + main() diff --git a/tools/python/run_CIs_for_external_pr.py b/tools/python/run_CIs_for_external_pr.py index 1546a9143831a..20e0134dd370a 100644 --- a/tools/python/run_CIs_for_external_pr.py +++ b/tools/python/run_CIs_for_external_pr.py @@ -19,11 +19,7 @@ def get_pipeline_names(): # windows "Windows ARM64 QNN CI Pipeline", "Windows x64 QNN CI Pipeline", - "Windows CPU CI Pipeline", - "Windows GPU CUDA CI Pipeline", - "Windows GPU DML CI Pipeline", "Windows GPU Doc Gen CI Pipeline", - "Windows GPU TensorRT CI Pipeline", "ONNX Runtime Web CI Pipeline", "Win_TRT_Minimal_CUDA_Test_CI", # linux @@ -33,8 +29,6 @@ def get_pipeline_names(): "Linux GPU TensorRT CI Pipeline", "Linux OpenVINO CI Pipeline", "Linux QNN CI Pipeline", - # mac - "MacOS CI Pipeline", # checks "onnxruntime-binary-size-checks-ci-pipeline", # big models @@ -45,7 +39,6 @@ def get_pipeline_names(): "Android CI Pipeline", "iOS CI Pipeline", "ONNX Runtime React Native CI Pipeline", - "CoreML CI Pipeline", "Linux DNNL CI Pipeline", "Linux MIGraphX CI Pipeline", "Linux ROCm CI Pipeline", diff --git a/tools/python/update_version.py b/tools/python/update_version.py index f6e7acb646b69..b7d2186024ff1 100755 --- a/tools/python/update_version.py +++ b/tools/python/update_version.py @@ -90,10 +90,9 @@ def run(args, cwd): args = ["cmd", "/c", *args] run(*args, cwd=cwd) - # check if node, npm and yarn are installed + # check if node and npm are installed run(["node", "--version"], cwd=js_root) run(["npm", "--version"], cwd=js_root) - run(["yarn", "--version"], cwd=js_root) # upgrade version for onnxruntime-common run(["npm", "version", version], cwd=os.path.join(js_root, "common")) @@ -109,7 +108,7 @@ def run(args, cwd): # upgrade version for onnxruntime-react-native run(["npm", "version", version], cwd=os.path.join(js_root, "react_native")) - run(["yarn", "upgrade", "onnxruntime-common"], cwd=os.path.join(js_root, "react_native")) + run(["npm", "install", "--package-lock-only", "--ignore-scripts"], cwd=os.path.join(js_root, "react_native")) # upgrade version.ts in each package run(["npm", "ci"], cwd=js_root) diff --git a/tools/python/util/__init__.py b/tools/python/util/__init__.py index a669963e84bcf..8631218ca9e00 100644 --- a/tools/python/util/__init__.py +++ b/tools/python/util/__init__.py @@ -7,7 +7,8 @@ from .run import run # noqa: F401 from .vcpkg_helpers import ( # noqa: F401 generate_android_triplets, - generate_posix_triplets, + generate_linux_triplets, + generate_macos_triplets, generate_vcpkg_triplets_for_emscripten, generate_windows_triplets, ) diff --git a/tools/python/util/android/android.py b/tools/python/util/android/android.py index 8f3ed97cae53f..cd420ca1483c7 100644 --- a/tools/python/util/android/android.py +++ b/tools/python/util/android/android.py @@ -46,18 +46,36 @@ def filename(name, windows_extension): def create_virtual_device(sdk_tool_paths: SdkToolPaths, system_image_package_name: str, avd_name: str): run(sdk_tool_paths.sdkmanager, "--install", system_image_package_name, input=b"y") - - run( - sdk_tool_paths.avdmanager, - "create", - "avd", - "--name", - avd_name, - "--package", - system_image_package_name, - "--force", - input=b"no", - ) + android_avd_home = os.environ["ANDROID_AVD_HOME"] + + if android_avd_home is not None: + if not os.path.exists(android_avd_home): + os.makedirs(android_avd_home) + run( + sdk_tool_paths.avdmanager, + "create", + "avd", + "--name", + avd_name, + "--package", + system_image_package_name, + "--force", + "--path", + android_avd_home, + input=b"no", + ) + else: + run( + sdk_tool_paths.avdmanager, + "create", + "avd", + "--name", + avd_name, + "--package", + system_image_package_name, + "--force", + input=b"no", + ) _process_creationflags = subprocess.CREATE_NEW_PROCESS_GROUP if is_windows() else 0 diff --git a/tools/python/util/vcpkg_helpers.py b/tools/python/util/vcpkg_helpers.py index d33b2f7675690..df457cdbf2b95 100644 --- a/tools/python/util/vcpkg_helpers.py +++ b/tools/python/util/vcpkg_helpers.py @@ -139,11 +139,11 @@ def generate_triplet_for_android( # Valid options are dynamic and static. Libraries can ignore this setting if they do not support the preferred linkage type. In our case, we prefer to use static libs. f.write("set(VCPKG_LIBRARY_LINKAGE static)\n") if not enable_rtti: - f.write("set(CMAKE_ANDROID_RTTI OFF)") + f.write("set(CMAKE_ANDROID_RTTI OFF)\n") if not enable_exception: - f.write("set(CMAKE_ANDROID_EXCEPTIONS OFF)") + f.write("set(CMAKE_ANDROID_EXCEPTIONS OFF)\n") if use_cpp_shared: - f.write("set(ANDROID_STL c++_shared)") + f.write("set(ANDROID_STL c++_shared)\n") ldflags = [] @@ -222,6 +222,7 @@ def generate_triplet_for_posix_platform( enable_asan: bool, crt_linkage: str, target_abi: str, + osx_deployment_target: str, ) -> None: """ Generate triplet file for POSIX platforms (Linux, macOS). @@ -235,6 +236,7 @@ def generate_triplet_for_posix_platform( enable_asan (bool): Flag indicating if AddressSanitizer is enabled. crt_linkage (str): The CRT linkage type ("static" or "dynamic"). target_abi (str): The target ABI, which maps to the VCPKG_TARGET_ARCHITECTURE variable. Valid options include x86, x64, arm, arm64, arm64ec, s390x, ppc64le, riscv32, riscv64, loongarch32, loongarch64, mips64. + osx_deployment_target (str, optional): The macOS deployment target version. The parameter sets the minimum macOS version for compiled binaries. It also changes what versions of the macOS platform SDK CMake will search for. See the CMake documentation for CMAKE_OSX_DEPLOYMENT_TARGET for more information. """ folder_name_parts = [] if enable_asan: @@ -341,6 +343,8 @@ def generate_triplet_for_posix_platform( else: osx_abi = target_abi f.write(f'set(VCPKG_OSX_ARCHITECTURES "{osx_abi}")\n') + if osx_deployment_target: + f.write(f'set(VCPKG_OSX_DEPLOYMENT_TARGET "{osx_deployment_target}")\n') f.write("set(CMAKE_POSITION_INDEPENDENT_CODE ON)\n") f.write( "list(APPEND VCPKG_CMAKE_CONFIGURE_OPTIONS --compile-no-warning-as-error -DBENCHMARK_ENABLE_WERROR=OFF)\n" @@ -425,12 +429,13 @@ def generate_vcpkg_triplets_for_emscripten(build_dir: str, emscripten_root: str) add_port_configs(f, True, True) -def generate_windows_triplets(build_dir: str) -> None: +def generate_windows_triplets(build_dir: str, toolset_version: str) -> None: """ Generate triplet files for Windows platforms. Args: build_dir (str): The directory to save the generated triplet files. + toolset_version (str, optional): The version of the platform toolset. """ # Below are all the CPU ARCHs we support on Windows. # ARM64 is for ARM64 processes that contains traditional ARM64 code. @@ -469,6 +474,8 @@ def generate_windows_triplets(build_dir: str) -> None: f.write(f"set(VCPKG_TARGET_ARCHITECTURE {target_abi})\n") f.write(f"set(VCPKG_CRT_LINKAGE {crt_linkage})\n") f.write("set(VCPKG_LIBRARY_LINKAGE static)\n") + if toolset_version: + f.write(f"set(VCPKG_PLATFORM_TOOLSET_VERSION {toolset_version})\n") cflags = ["/MP", "/DWIN32", "/D_WINDOWS"] if enable_binskim: cflags += [ @@ -501,32 +508,58 @@ def generate_windows_triplets(build_dir: str) -> None: add_port_configs(f, enable_exception, False) -def generate_posix_triplets(build_dir: str) -> None: +def generate_linux_triplets(build_dir: str) -> None: """ - Generate triplet files for POSIX platforms (Linux, macOS). + Generate triplet files for Linux platforms. Args: build_dir (str): The directory to save the generated triplet files. """ - for os_name in ["linux", "osx"]: - if os_name == "linux": - target_abis = ["x86", "x64", "arm", "arm64", "s390x", "ppc64le", "riscv64", "loongarch64", "mips64"] - else: - target_abis = ["x64", "arm64", "universal2"] - for enable_rtti in [True, False]: - for enable_exception in [True, False]: - for enable_binskim in [True, False]: - for enable_asan in [True, False]: - if enable_asan and enable_binskim: - continue - for target_abi in target_abis: - generate_triplet_for_posix_platform( - build_dir, - os_name, - enable_rtti, - enable_exception, - enable_binskim, - enable_asan, - "dynamic", - target_abi, - ) + target_abis = ["x86", "x64", "arm", "arm64", "s390x", "ppc64le", "riscv64", "loongarch64", "mips64"] + for enable_rtti in [True, False]: + for enable_exception in [True, False]: + for enable_binskim in [True, False]: + for enable_asan in [True, False]: + if enable_asan and enable_binskim: + continue + for target_abi in target_abis: + generate_triplet_for_posix_platform( + build_dir, + "linux", + enable_rtti, + enable_exception, + enable_binskim, + enable_asan, + "dynamic", + target_abi, + None, + ) + + +def generate_macos_triplets(build_dir: str, osx_deployment_target: str) -> None: + """ + Generate triplet files for macOS platforms. + + Args: + build_dir (str): The directory to save the generated triplet files. + osx_deployment_target (str, optional): The macOS deployment target version. + """ + target_abis = ["x64", "arm64", "universal2"] + for enable_rtti in [True, False]: + for enable_exception in [True, False]: + for enable_binskim in [True, False]: + for enable_asan in [True, False]: + if enable_asan and enable_binskim: + continue + for target_abi in target_abis: + generate_triplet_for_posix_platform( + build_dir, + "osx", + enable_rtti, + enable_exception, + enable_binskim, + enable_asan, + "dynamic", + target_abi, + osx_deployment_target, + ) diff --git a/winml/adapter/winml_adapter_model.cpp b/winml/adapter/winml_adapter_model.cpp index 195bf6e5f0ffd..cf02c6fa2328b 100644 --- a/winml/adapter/winml_adapter_model.cpp +++ b/winml/adapter/winml_adapter_model.cpp @@ -593,13 +593,13 @@ ORT_API_STATUS_IMPL( input.set_name(input_name); if (info->type == ONNXType::ONNX_TYPE_TENSOR) { - auto num_dims = info->data->shape.NumDimensions(); + auto num_dims = info->tensor_type_info->shape.NumDimensions(); CreateTypeProto_Tensor( input.mutable_type()->mutable_tensor_type(), input_name, - (num_dims == 0) ? nullptr : &info->data->shape[0], + (num_dims == 0) ? nullptr : &info->tensor_type_info->shape[0], num_dims, - ONNXTensorElementDataTypeToTensorProto_DataType(info->data->type) + ONNXTensorElementDataTypeToTensorProto_DataType(info->tensor_type_info->type) ); } return nullptr; @@ -619,12 +619,12 @@ ORT_API_STATUS_IMPL( ONNX_NAMESPACE::TensorProto& input = *graph.add_initializer(); input.set_name(input_name); - auto num_dims = info->data->shape.NumDimensions(); + auto num_dims = info->tensor_type_info->shape.NumDimensions(); for (size_t i = 0; i < num_dims; i++) { - input.add_dims(info->data->shape[i]); + input.add_dims(info->tensor_type_info->shape[i]); } - input.set_data_type(ONNXTensorElementDataTypeToTensorProto_DataType(info->data->type)); + input.set_data_type(ONNXTensorElementDataTypeToTensorProto_DataType(info->tensor_type_info->type)); auto tensor = value->GetMutable(); input.set_raw_data(tensor->DataRaw(), tensor->SizeInBytes()); @@ -645,9 +645,9 @@ ORT_API_STATUS_IMPL( CreateTypeProto_Tensor( output.mutable_type()->mutable_tensor_type(), output_name, - &info->data->shape[0], - info->data->shape.NumDimensions(), - ONNXTensorElementDataTypeToTensorProto_DataType(info->data->type) + &info->tensor_type_info->shape[0], + info->tensor_type_info->shape.NumDimensions(), + ONNXTensorElementDataTypeToTensorProto_DataType(info->tensor_type_info->type) ); } return nullptr;